From 402fad5c5ea8c1b9238b5b3f66bb15418699ae6b Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Mon, 7 Nov 2022 01:48:44 +0000 Subject: [PATCH 001/151] Added narrow interface bls-signatures --- .gitmodules | 3 + libraries/chain/abi_serializer.cpp | 3 + libraries/chain/controller.cpp | 10 + .../eosio/chain/protocol_feature_manager.hpp | 1 + libraries/chain/include/eosio/chain/types.hpp | 7 + .../eos-vm-oc/intrinsic_mapping.hpp | 6 +- .../eosio/chain/webassembly/interface.hpp | 8 + libraries/chain/protocol_feature_manager.cpp | 9 + libraries/chain/webassembly/crypto.cpp | 86 ++++++++ .../chain/webassembly/runtimes/eos-vm.cpp | 7 + libraries/libfc/CMakeLists.txt | 6 +- .../include/fc/crypto/bls_private_key.hpp | 81 ++++++++ .../include/fc/crypto/bls_public_key.hpp | 79 ++++++++ .../libfc/include/fc/crypto/bls_signature.hpp | 84 ++++++++ .../libfc/include/fc/crypto/bls_utils.hpp | 66 ++++++ libraries/libfc/libraries/bls-signatures | 1 + .../libfc/src/crypto/bls_private_key.cpp | 174 ++++++++++++++++ libraries/libfc/src/crypto/bls_public_key.cpp | 91 +++++++++ libraries/libfc/src/crypto/bls_signature.cpp | 107 ++++++++++ libraries/libfc/src/crypto/bls_utils.cpp | 12 ++ libraries/libfc/test/CMakeLists.txt | 4 + libraries/libfc/test/test_bls.cpp | 190 ++++++++++++++++++ 22 files changed, 1033 insertions(+), 2 deletions(-) create mode 100644 libraries/libfc/include/fc/crypto/bls_private_key.hpp create mode 100644 libraries/libfc/include/fc/crypto/bls_public_key.hpp create mode 100644 libraries/libfc/include/fc/crypto/bls_signature.hpp create mode 100644 libraries/libfc/include/fc/crypto/bls_utils.hpp create mode 160000 libraries/libfc/libraries/bls-signatures create mode 100644 libraries/libfc/src/crypto/bls_private_key.cpp create mode 100644 libraries/libfc/src/crypto/bls_public_key.cpp create mode 100644 libraries/libfc/src/crypto/bls_signature.cpp create mode 100644 libraries/libfc/src/crypto/bls_utils.cpp create mode 100644 libraries/libfc/test/test_bls.cpp diff --git a/.gitmodules b/.gitmodules index 2280151a71..347174d5d8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule "libraries/libfc/libraries/ff"] path = libraries/libfc/libraries/ff url = https://github.com/AntelopeIO/libff +[submodule "libraries/libfc/libraries/bls-signatures"] + path = libraries/libfc/libraries/bls-signatures + url = https://github.com/systemzax/bls-signatures diff --git a/libraries/chain/abi_serializer.cpp b/libraries/chain/abi_serializer.cpp index 45e84e1b16..6b3d3c05bc 100644 --- a/libraries/chain/abi_serializer.cpp +++ b/libraries/chain/abi_serializer.cpp @@ -122,6 +122,9 @@ namespace eosio { namespace chain { built_in_types.emplace("public_key", pack_unpack_deadline()); built_in_types.emplace("signature", pack_unpack_deadline()); + built_in_types.emplace("bls_public_key", pack_unpack_deadline()); + built_in_types.emplace("bls_signature", pack_unpack_deadline()); + built_in_types.emplace("symbol", pack_unpack()); built_in_types.emplace("symbol_code", pack_unpack()); built_in_types.emplace("asset", pack_unpack()); diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 4e9c1439bc..3316c13f18 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -320,6 +320,7 @@ struct controller_impl { set_activation_handler(); set_activation_handler(); set_activation_handler(); + set_activation_handler(); self.irreversible_block.connect([this](const block_state_ptr& bsp) { wasmif.current_lib(bsp->block_num); @@ -3692,6 +3693,15 @@ void controller_impl::on_activation +void controller_impl::on_activation() { + db.modify( db.get(), [&]( auto& ps ) { + add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "bls_verify" ); + add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "bls_aggregate_pubkeys" ); + add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "bls_aggregate_sigs" ); + add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "bls_aggregate_verify" ); + } ); +} /// End of protocol feature activation handlers } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp index 4838097d64..ef75656415 100644 --- a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp +++ b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp @@ -35,6 +35,7 @@ enum class builtin_protocol_feature_t : uint32_t { configurable_wasm_limits = 18, // configurable_wasm_limits2, crypto_primitives = 19, get_block_num = 20, + aggregate_signatures = 21, reserved_private_fork_protocol_features = 500000, }; diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index 97b64ed70a..b13119cb21 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -78,6 +79,12 @@ namespace eosio { namespace chain { using public_key_type = fc::crypto::public_key; using private_key_type = fc::crypto::private_key; using signature_type = fc::crypto::signature; + + + using bls_public_key_type = fc::crypto::blslib::bls_public_key; + using bls_signature_type = fc::crypto::blslib::bls_signature; + + #if BOOST_VERSION >= 107100 // configurable boost deque performs much better than std::deque in our use cases using block_1024_option_t = boost::container::deque_options< boost::container::block_size<1024u> >::type; diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp index 464893530e..c27e46428c 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp @@ -267,7 +267,11 @@ inline constexpr auto get_intrinsic_table() { "env.sha3", "env.blake2_f", "env.k1_recover", - "env.get_block_num" + "env.get_block_num", + "env.bls_verify", + "env.bls_aggregate_pubkeys", + "env.bls_aggregate_sigs", + "env.bls_aggregate_verify" ); } inline constexpr std::size_t find_intrinsic_index(std::string_view hf) { diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index 08f0eba6aa..a2df944317 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -1785,6 +1785,14 @@ namespace webassembly { */ int32_t k1_recover( span signature, span digest, span pub) const; + bool bls_verify( span signature, span digest, span pub) const; + + int32_t bls_aggregate_pubkeys( span pubkeys, span aggregate) const; + int32_t bls_aggregate_sigs( span signatures, span aggregate) const; + + bool bls_aggregate_verify( span signature, span digests, span pubs) const; + + // compiler builtins api void __ashlti3(legacy_ptr, uint64_t, uint64_t, uint32_t) const; void __ashrti3(legacy_ptr, uint64_t, uint64_t, uint32_t) const; diff --git a/libraries/chain/protocol_feature_manager.cpp b/libraries/chain/protocol_feature_manager.cpp index 9173263f64..ab2b9e2a87 100644 --- a/libraries/chain/protocol_feature_manager.cpp +++ b/libraries/chain/protocol_feature_manager.cpp @@ -257,6 +257,15 @@ Adds new cryptographic host functions Builtin protocol feature: GET_BLOCK_NUM Enables new `get_block_num` intrinsic which returns the current block number. +*/ + {} + } ) + ( builtin_protocol_feature_t::aggregate_signatures, builtin_protocol_feature_spec{ + "AGGREGATE_SIGNATURES", + fc::variant("997de2624c039e38993953ff1091aeb1ecff723d06fe78a5ade08931b0b22896").as(), + // SHA256 hash of the raw message below within the comment delimiters (do not modify message below). +/* +Builtin protocol feature: AGGREGATE_SIGNATURES */ {} } ) diff --git a/libraries/chain/webassembly/crypto.cpp b/libraries/chain/webassembly/crypto.cpp index 62f44392a1..c687ab03a8 100644 --- a/libraries/chain/webassembly/crypto.cpp +++ b/libraries/chain/webassembly/crypto.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace { uint32_t ceil_log2(uint32_t n) @@ -270,5 +271,90 @@ namespace eosio { namespace chain { namespace webassembly { std::memcpy( pub.data(), res.data(), res.size() ); return return_code::success; } + + + bool interface::bls_verify( span signature, span digest, span pub) const { + + + fc::crypto::blslib::bls_signature u_sig; + fc::crypto::blslib::bls_public_key u_pub; + vector u_digest; + + datastream s_sig( signature.data(), signature.size() ); + datastream s_pub( pub.data(), pub.size() ); + datastream s_digest( digest.data(), digest.size() ); + + fc::raw::unpack( s_sig, u_sig ); + fc::raw::unpack( s_pub, u_pub ); + fc::raw::unpack( s_digest, u_digest ); + + std::cerr << u_pub.to_string() << "\n"; + std::cerr << u_sig.to_string() << "\n"; + + bool result = fc::crypto::blslib::verify(u_pub, u_digest, u_sig); + + return result; + + } + + int32_t interface::bls_aggregate_pubkeys( span pubkeys, span aggregate) const { + + vector u_pubkeys; + + datastream s_pubkeys( pubkeys.data(), pubkeys.size() ); + + fc::raw::unpack( s_pubkeys, u_pubkeys ); + + fc::crypto::blslib::bls_public_key agg_pubkey = fc::crypto::blslib::aggregate(u_pubkeys); + + auto packed = fc::raw::pack(agg_pubkey); + + auto copy_size = std::min(aggregate.size(), packed.size()); + + std::memcpy(aggregate.data(), packed.data(), copy_size); + + return packed.size(); + + } + + int32_t interface::bls_aggregate_sigs( span signatures, span aggregate) const { + + vector u_sigs; + + datastream s_sigs( signatures.data(), signatures.size() ); + + fc::raw::unpack( s_sigs, u_sigs ); + + fc::crypto::blslib::bls_signature agg_sig = fc::crypto::blslib::aggregate(u_sigs); + + auto packed = fc::raw::pack(agg_sig); + + auto copy_size = std::min(aggregate.size(), packed.size()); + + std::memcpy(aggregate.data(), packed.data(), copy_size); + + return packed.size(); + + } + + bool interface::bls_aggregate_verify( span signature, span digests, span pubs) const { + + fc::crypto::blslib::bls_signature u_sig; + vector u_pubs; + vector> u_digests; + + datastream s_sig( signature.data(), signature.size() ); + datastream s_pubs( pubs.data(), pubs.size() ); + datastream s_digests( digests.data(), digests.size() ); + + fc::raw::unpack( s_sig, u_sig ); + fc::raw::unpack( s_pubs, u_pubs ); + fc::raw::unpack( s_digests, u_digests ); + + bool result = fc::crypto::blslib::aggregate_verify(u_pubs, u_digests, u_sig); + + return result; + + } }}} // ns eosio::chain::webassembly diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index 1d78a1a7fa..26dcfec6be 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -629,6 +629,13 @@ REGISTER_CF_HOST_FUNCTION( blake2_f ); REGISTER_CF_HOST_FUNCTION( sha3 ); REGISTER_CF_HOST_FUNCTION( k1_recover ); +// aggregate_signatures protocol feature +REGISTER_CF_HOST_FUNCTION( bls_verify ); +REGISTER_CF_HOST_FUNCTION( bls_aggregate_pubkeys ); +REGISTER_CF_HOST_FUNCTION( bls_aggregate_sigs ); +REGISTER_CF_HOST_FUNCTION( bls_aggregate_verify ); + + } // namespace webassembly } // namespace chain } // namespace eosio diff --git a/libraries/libfc/CMakeLists.txt b/libraries/libfc/CMakeLists.txt index 4f58db0aa0..19614cb81d 100644 --- a/libraries/libfc/CMakeLists.txt +++ b/libraries/libfc/CMakeLists.txt @@ -6,6 +6,7 @@ set( USE_ASM OFF CACHE BOOL "" FORCE) set( IS_LIBFF_PARENT OFF CACHE BOOL "" FORCE) set( FF_INSTALL_COMPONENT "${FC_INSTALL_COMPONENT}") add_subdirectory( libraries/ff ) +add_subdirectory( libraries/bls-signatures ) set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) @@ -64,6 +65,9 @@ set( fc_sources src/crypto/public_key.cpp src/crypto/private_key.cpp src/crypto/signature.cpp + src/crypto/bls_private_key.cpp + src/crypto/bls_public_key.cpp + src/crypto/bls_signature.cpp src/crypto/alt_bn128.cpp src/crypto/modular_arithmetic.cpp src/crypto/blake2.cpp @@ -138,7 +142,7 @@ if(APPLE) find_library(security_framework Security) find_library(corefoundation_framework CoreFoundation) endif() -target_link_libraries( fc PUBLIC ff +target_link_libraries( fc PUBLIC ff bls Boost::date_time Boost::filesystem Boost::chrono Boost::iostreams Threads::Threads OpenSSL::Crypto OpenSSL::SSL ZLIB::ZLIB ${PLATFORM_SPECIFIC_LIBS} ${CMAKE_DL_LIBS} secp256k1 ${security_framework} ${corefoundation_framework} ) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp new file mode 100644 index 0000000000..37b17ef343 --- /dev/null +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -0,0 +1,81 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include + +namespace fc { namespace crypto { namespace blslib { + + using namespace bls; + + namespace config { + constexpr const char* bls_private_key_base_prefix = "PVT"; + constexpr const char* bls_private_key_prefix = "BLS"; + }; + + class bls_private_key + { + public: + + bls_private_key() = default; + bls_private_key( bls_private_key&& ) = default; + bls_private_key( const bls_private_key& ) = default; + bls_private_key& operator= (const bls_private_key& ) = default; + + bls_private_key( vector seed ){ + _seed = seed; + } + + bls_public_key get_public_key() const; + bls_signature sign( vector message ) const; + sha512 generate_shared_secret( const bls_public_key& pub ) const; + + std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; + + static bls_private_key generate() { + + char* r = (char*) malloc(32); + + rand_bytes(r, 32); + + vector v(r, r+32); + + return bls_private_key(v); + } + +/* template< typename KeyType = r1::private_key_shim > + static bls_private_key generate_r1() { + return bls_private_key(storage_type(KeyType::generate())); + }*/ + + static bls_private_key regenerate( vector seed ) { + return bls_private_key(seed); + } + + // serialize to/from string + explicit bls_private_key(const string& base58str); + + std::string serialize(); + + private: + vector _seed; + + friend bool operator == ( const bls_private_key& p1, const bls_private_key& p2); + friend bool operator != ( const bls_private_key& p1, const bls_private_key& p2); + friend bool operator < ( const bls_private_key& p1, const bls_private_key& p2); + friend struct reflector; + }; // bls_private_key + +} } } // fc::crypto::blslib + +namespace fc { + void to_variant(const crypto::blslib::bls_private_key& var, variant& vo, const fc::yield_function_t& yield = fc::yield_function_t()); + + void from_variant(const variant& var, crypto::blslib::bls_private_key& vo); +} // namespace fc + +FC_REFLECT(fc::crypto::blslib::bls_private_key, (_seed) ) diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp new file mode 100644 index 0000000000..5b98eccbfe --- /dev/null +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -0,0 +1,79 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +//#include + +namespace fc { namespace crypto { namespace blslib { + + using namespace std; + + namespace config { + constexpr const char* bls_public_key_legacy_prefix = "EOS"; + constexpr const char* bls_public_key_base_prefix = "PUB"; + constexpr const char* bls_public_key_prefix = "BLS"; + + }; + + class bls_public_key + { + public: + + bls_public_key() = default; + bls_public_key( bls_public_key&& ) = default; + bls_public_key( const bls_public_key& ) = default; + bls_public_key& operator= (const bls_public_key& ) = default; + + bls_public_key( std::vector pkey ){ + _pkey = pkey; + } + +/* bls_public_key( G1Element pkey ){ + _pkey = pkey.Serialize(); + } +*/ + //bls_public_key( const bls_signature& c, const sha256& digest, bool check_canonical = true ); + +/* bls_public_key( storage_type&& other_storage ) + :_storage(forward(other_storage)) + {} +*/ + bool valid()const; + + size_t which()const; + + // serialize to/from string + explicit bls_public_key(const string& base58str); + //std::string to_string() const; + //std::string to_string() ; + + std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; + + //storage_type _storage; + + std::vector _pkey; + + private: + + + 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); + friend struct reflector; + friend class bls_private_key; + }; // bls_public_key + +} } } // fc::crypto::blslib + +namespace fc { + void to_variant(const crypto::blslib::bls_public_key& var, variant& vo, const fc::yield_function_t& yield = fc::yield_function_t()); + + void from_variant(const variant& var, crypto::blslib::bls_public_key& vo); +} // namespace fc + +FC_REFLECT(fc::crypto::blslib::bls_public_key, (_pkey) ) diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp new file mode 100644 index 0000000000..0bf0c6c4a3 --- /dev/null +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -0,0 +1,84 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +//#include + +namespace fc { namespace crypto { namespace blslib { + + using namespace std; + + namespace config { + constexpr const char* bls_signature_base_prefix = "SIG"; + constexpr const char* bls_signature_prefix = "BLS"; + }; + + class bls_signature + { + public: + //using storage_type = ecc::signature_shim;//std::variant; + + bls_signature() = default; + bls_signature( bls_signature&& ) = default; + bls_signature( const bls_signature& ) = default; + bls_signature& operator= (const bls_signature& ) = default; + + bls_signature( std::vector sig ){ + _sig = sig; + } + +/* bls_signature( G2Element sig ){ + _sig = sig.Serialize(); + } +*/ + // serialize to/from string + explicit bls_signature(const string& base58str); + std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; + + size_t which() const; + + size_t variable_size() const; + + + std::vector _sig; + + private: + + //storage_type _storage; + +/* bls_signature( storage_type&& other_storage ) + :_storage(std::forward(other_storage)) + {} +*/ + //friend bool operator == ( const bls_signature& p1, const bls_signature& p2); + //friend bool operator != ( const bls_signature& p1, const bls_signature& p2); + //friend bool operator < ( const bls_signature& p1, const bls_signature& p2); + friend std::size_t hash_value(const bls_signature& b); //not cryptographic; for containers + friend struct reflector; + friend class bls_private_key; + friend class bls_public_key; + }; // bls_public_key + + //size_t hash_value(const bls_signature& b); + +} } } // fc::crypto::blslib + +namespace fc { + void to_variant(const crypto::blslib::bls_signature& var, variant& vo, const fc::yield_function_t& yield = fc::yield_function_t()); + + void from_variant(const variant& var, crypto::blslib::bls_signature& vo); +} // namespace fc + +namespace std { + template <> struct hash { + std::size_t operator()(const fc::crypto::blslib::bls_signature& k) const { + //return fc::crypto::hash_value(k); + } + }; +} // std + +FC_REFLECT(fc::crypto::blslib::bls_signature, (_sig) ) diff --git a/libraries/libfc/include/fc/crypto/bls_utils.hpp b/libraries/libfc/include/fc/crypto/bls_utils.hpp new file mode 100644 index 0000000000..de046f23cf --- /dev/null +++ b/libraries/libfc/include/fc/crypto/bls_utils.hpp @@ -0,0 +1,66 @@ +#pragma once +#include +#include +#include +#include +//#include + +namespace fc { namespace crypto { namespace blslib { + + static bls_private_key generate() { + + char* r = (char*) malloc(32); + + rand_bytes(r, 32); + + vector v(r, r+32); + + return bls_private_key(v); + + } + + static bool verify( const bls_public_key &pubkey, + const vector &message, + const bls_signature &signature){ + + return PopSchemeMPL().Verify(pubkey._pkey, message, signature._sig); + + }; + + static bls_public_key aggregate( const vector &keys){ + + G1Element aggKey; + + for (size_t i = 0 ; i < keys.size(); i++){ + aggKey += G1Element::FromByteVector(keys[i]._pkey); + } + + return bls_public_key(aggKey.Serialize()); + + }; + + static bls_signature aggregate( const vector &signatures){ + + vector> v_sigs; + + for (size_t i = 0 ; i < signatures.size(); i++) + v_sigs.push_back(signatures[i]._sig); + + return bls_signature(PopSchemeMPL().Aggregate(v_sigs)); + + }; + + static bool aggregate_verify( const vector &pubkeys, + const vector> &messages, + const bls_signature &signature){ + + vector> v_pubkeys; + + for (size_t i = 0 ; i < pubkeys.size(); i++) + v_pubkeys.push_back(pubkeys[i]._pkey); + + return PopSchemeMPL().AggregateVerify(v_pubkeys, messages, signature._sig); + + }; + +} } } // fc::crypto::blslib diff --git a/libraries/libfc/libraries/bls-signatures b/libraries/libfc/libraries/bls-signatures new file mode 160000 index 0000000000..3980ffea61 --- /dev/null +++ b/libraries/libfc/libraries/bls-signatures @@ -0,0 +1 @@ +Subproject commit 3980ffea618160a6b8ef0edc427721a796de957f diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp new file mode 100644 index 0000000000..009b771ac7 --- /dev/null +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -0,0 +1,174 @@ +#include +#include +#include + +namespace fc { namespace crypto { namespace blslib { + + using namespace std; + + bls_public_key bls_private_key::get_public_key() const + { + G1Element pk = AugSchemeMPL().KeyGen(_seed).GetG1Element(); + + return bls_public_key(pk.Serialize()); + } + + bls_signature bls_private_key::sign( vector message ) const + { + + PrivateKey sk = AugSchemeMPL().KeyGen(_seed); + + G2Element s = PopSchemeMPL().Sign(sk, message); + return bls_signature(s.Serialize()); + } + + /*struct public_key_visitor : visitor { + template + bls_public_key::storage_type operator()(const KeyType& key) const + { + //return bls_public_key::storage_type(key.get_public_key()); + } + }; + + struct sign_visitor : visitor { + sign_visitor( const sha256& digest, bool require_canonical ) + :_digest(digest) + ,_require_canonical(require_canonical) + {} + + template + bls_signature::storage_type operator()(const KeyType& key) const + { + return bls_signature::storage_type(key.sign(_digest, _require_canonical)); + } + + const sha256& _digest; + bool _require_canonical; + }; + + bls_signature bls_private_key::sign( vector message ) const + { + //return bls_signature(std::visit(sign_visitor(digest, require_canonical), _seed)); + } + + struct generate_shared_secret_visitor : visitor { + generate_shared_secret_visitor( const bls_public_key::storage_type& pub_storage ) + :_pub_storage(pub_storage) + {} + + template + sha512 operator()(const KeyType& key) const + { + using PublicKeyType = typename KeyType::public_key_type; + return key.generate_shared_secret(std::template get(_pub_storage)); + } + + const bls_public_key::storage_type& _pub_storage; + }; + + sha512 bls_private_key::generate_shared_secret( const bls_public_key& pub ) const + + template + string to_wif( const Data& secret, const fc::yield_function_t& yield ) + { + { + return std::visit(generate_shared_secret_visitor(pub._storage), _seed); + }*/ + /* const size_t size_of_data_to_hash = sizeof(typename Data::data_type) + 1; + const size_t size_of_hash_bytes = 4; + char data[size_of_data_to_hash + size_of_hash_bytes]; + data[0] = (char)0x80; // this is the Bitcoin MainNet code + memcpy(&data[1], (const char*)&secret.serialize(), sizeof(typename Data::data_type)); + sha256 digest = sha256::hash(data, size_of_data_to_hash); + digest = sha256::hash(digest); + memcpy(data + size_of_data_to_hash, (char*)&digest, size_of_hash_bytes); + return to_base58(data, sizeof(data), yield); + } +*/ + + template + Data from_wif( const string& wif_key ) + { + /* auto wif_bytes = from_base58(wif_key); + FC_ASSERT(wif_bytes.size() >= 5); + auto key_bytes = vector(wif_bytes.begin() + 1, wif_bytes.end() - 4); + fc::sha256 check = fc::sha256::hash(wif_bytes.data(), wif_bytes.size() - 4); + fc::sha256 check2 = fc::sha256::hash(check); + + FC_ASSERT(memcmp( (char*)&check, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 || + memcmp( (char*)&check2, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 ); + + return Data(fc::variant(key_bytes).as());*/ + } + + static vector priv_parse_base58(const string& base58str) + { + /* const auto pivot = base58str.find('_'); + + if (pivot == std::string::npos) { + // wif import + using default_type = std::variant_alternative_t<0, bls_private_key::storage_type>; + return bls_private_key::storage_type(from_wif(base58str)); + } else { + constexpr auto prefix = config::private_key_base_prefix; + const auto prefix_str = base58str.substr(0, pivot); + FC_ASSERT(prefix == prefix_str, "Private Key has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str)); + + auto data_str = base58str.substr(pivot + 1); + FC_ASSERT(!data_str.empty(), "Private Key has no data: ${str}", ("str", base58str)); + return base58_str_parser::apply(data_str); + }*/ + } + + bls_private_key::bls_private_key(const std::string& base58str) + :_seed(priv_parse_base58(base58str)) + {} + + std::string bls_private_key::to_string(const fc::yield_function_t& yield) const + { + + /*PrivateKey pk = AugSchemeMPL().KeyGen(_seed); + + vector pkBytes pk.Serialize() + + auto data_str = Util::HexStr(pkBytes); + return std::string(config::private_key_base_prefix) + "_" + data_str;*/ + } + +/* std::string bls_private_key::serialize(){ + + PrivateKey sk = AugSchemeMPL().KeyGen(_seed); + + return Util::HexStr(sk.Serialize()); + }*/ + + std::ostream& operator<<(std::ostream& s, const bls_private_key& k) { + s << "bls_private_key(" << k.to_string() << ')'; + return s; + } +/* + bool operator == ( const bls_private_key& p1, const bls_private_key& p2) { + + return eq_comparator>::apply(p1._seed, p2._seed); + } + + bool operator < ( const bls_private_key& p1, const bls_private_key& p2){ + + + return less_comparator>::apply(p1._seed, p2._seed); + }*/ +} } } // fc::crypto::blslib + +namespace fc +{ + void to_variant(const fc::crypto::blslib::bls_private_key& var, variant& vo, const fc::yield_function_t& yield) + { + vo = var.to_string(yield); + } + + void from_variant(const variant& var, fc::crypto::blslib::bls_private_key& vo) + { + vo = fc::crypto::blslib::bls_private_key(var.as_string()); + } + +} // fc diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp new file mode 100644 index 0000000000..b72f71ded5 --- /dev/null +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -0,0 +1,91 @@ +#include +#include +#include + +namespace fc { namespace crypto { namespace blslib { + + /* struct recovery_visitor : fc::visitor { + recovery_visitor(const sha256& digest, bool check_canonical) + :_digest(digest) + ,_check_canonical(check_canonical) + {} + + template + bls_public_key::storage_type operator()(const SignatureType& s) const { + return bls_public_key::storage_type(s.recover(_digest, _check_canonical)); + } + + const sha256& _digest; + bool _check_canonical; + }; + + bls_public_key::bls_public_key( const bls_signature& c, const sha256& digest, bool check_canonical ) + :_storage(std::visit(recovery_visitor(digest, check_canonical), c._storage)) + { + } + + size_t bls_public_key::which() const { + return _storage.index(); + }*/ + + static vector parse_base58(const std::string& base58str) + { + + constexpr auto prefix = config::bls_public_key_base_prefix; + const auto pivot = base58str.find('_'); + const auto prefix_str = base58str.substr(0, pivot); + auto data_str = base58str.substr(pivot + 1); + + std::vector v1 = fc::from_base58(data_str); + + std::vector v2; + std::copy(v1.begin(), v1.end(), std::back_inserter(v2)); + + return v2; + + } + + bls_public_key::bls_public_key(const std::string& base58str) + :_pkey(parse_base58(base58str)) + {} + + + bool bls_public_key::valid()const + { + //return std::visit(is_valid_visitor(), _storage); + } + + + std::string bls_public_key::to_string(const fc::yield_function_t& yield)const { + + std::vector v2; + std::copy(_pkey.begin(), _pkey.end(), std::back_inserter(v2)); + + std::string data_str = fc::to_base58(v2, yield); + + //std::string data_str = Util::HexStr(_pkey); + + return std::string(config::bls_public_key_base_prefix) + "_" + data_str; + + } + + std::ostream& operator<<(std::ostream& s, const bls_public_key& k) { + s << "bls_public_key(" << k.to_string() << ')'; + return s; + } + +} } } // fc::crypto::blslib + +namespace fc +{ + using namespace std; + void to_variant(const fc::crypto::blslib::bls_public_key& var, fc::variant& vo, const fc::yield_function_t& yield) + { + vo = var.to_string(yield); + } + + void from_variant(const fc::variant& var, fc::crypto::blslib::bls_public_key& vo) + { + vo = fc::crypto::blslib::bls_public_key(var.as_string()); + } +} // fc diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp new file mode 100644 index 0000000000..83c54bed8d --- /dev/null +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -0,0 +1,107 @@ +#include +#include +#include + +namespace fc { namespace crypto { namespace blslib { + + struct hash_visitor : public fc::visitor { +/* template + size_t operator()(const SigType& sig) const { + static_assert(sizeof(sig._data.data) == 65, "sig size is expected to be 65"); + //signatures are two bignums: r & s. Just add up least significant digits of the two + return *(size_t*)&sig._data.data[32-sizeof(size_t)] + *(size_t*)&sig._data.data[64-sizeof(size_t)]; + } + + size_t operator()(const webauthn::bls_signature& sig) const { + return sig.get_hash(); + }*/ + }; + + static vector sig_parse_base58(const std::string& base58str) + { try { + + + const auto pivot = base58str.find('_'); + auto base_str = base58str.substr(pivot + 1); + const auto pivot2 = base_str.find('_'); + auto data_str = base_str.substr(pivot2 + 1); + + std::vector v1 = fc::from_base58(data_str); + + std::vector v2; + std::copy(v1.begin(), v1.end(), std::back_inserter(v2)); + + return v2; + + } FC_RETHROW_EXCEPTIONS( warn, "error parsing bls_signature", ("str", base58str ) ) } + + bls_signature::bls_signature(const std::string& base58str) + :_sig(sig_parse_base58(base58str)) + {} + + size_t bls_signature::which() const { + //return _storage.index(); + } + + + //template struct overloaded : Ts... { using Ts::operator()...; }; + //template overloaded(Ts...) -> overloaded; + + size_t bls_signature::variable_size() const { + /* return std::visit(overloaded { + [&](const auto& k1r1) { + return static_cast(0); + }, + [&](const webauthn::bls_signature& wa) { + return static_cast(wa.variable_size()); + } + }, _storage);*/ + } + + std::string bls_signature::to_string(const fc::yield_function_t& yield) const + { + + std::vector v2; + std::copy(_sig.begin(), _sig.end(), std::back_inserter(v2)); + + std::string data_str = fc::to_base58(v2, yield); + + return std::string(config::bls_signature_base_prefix) + "_" + std::string(config::bls_signature_prefix) + "_" + data_str; + + } + + std::ostream& operator<<(std::ostream& s, const bls_signature& k) { + s << "bls_signature(" << k.to_string() << ')'; + return s; + } +/* + bool operator == ( const bls_signature& p1, const bls_signature& p2) { + return eq_comparator::apply(p1._storage, p2._storage); + } + + bool operator != ( const bls_signature& p1, const bls_signature& p2) { + return !eq_comparator::apply(p1._storage, p2._storage); + } + + bool operator < ( const bls_signature& p1, const bls_signature& p2) + { + return less_comparator::apply(p1._storage, p2._storage); + } +*/ + size_t hash_value(const bls_signature& b) { + // return std::visit(hash_visitor(), b._storage); + } +} } } // fc::crypto::blslib + +namespace fc +{ + void to_variant(const fc::crypto::blslib::bls_signature& var, fc::variant& vo, const fc::yield_function_t& yield) + { + vo = var.to_string(yield); + } + + void from_variant(const fc::variant& var, fc::crypto::blslib::bls_signature& vo) + { + vo = fc::crypto::blslib::bls_signature(var.as_string()); + } +} // fc diff --git a/libraries/libfc/src/crypto/bls_utils.cpp b/libraries/libfc/src/crypto/bls_utils.cpp new file mode 100644 index 0000000000..30aab8e3dd --- /dev/null +++ b/libraries/libfc/src/crypto/bls_utils.cpp @@ -0,0 +1,12 @@ +#pragma once +#include + +namespace fc { namespace crypto { namespace blslib { + + static bool verify( const blslib::bls_public_key &pubkey, + const vector &message, + const bls_signature &signature){ + + } + +} } } // fc::crypto::blslib diff --git a/libraries/libfc/test/CMakeLists.txt b/libraries/libfc/test/CMakeLists.txt index 14c1cbf59b..9b6077befe 100644 --- a/libraries/libfc/test/CMakeLists.txt +++ b/libraries/libfc/test/CMakeLists.txt @@ -15,3 +15,7 @@ add_executable( test_filesystem test_filesystem.cpp ) target_link_libraries( test_filesystem fc ) add_test(NAME test_filesystem COMMAND test_filesystem WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +add_executable( test_bls test_bls.cpp ) +target_link_libraries( test_bls fc ) +add_test(NAME test_bls COMMAND libraries/libfc/test/test_bls WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) \ No newline at end of file diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp new file mode 100644 index 0000000000..d568095f82 --- /dev/null +++ b/libraries/libfc/test/test_bls.cpp @@ -0,0 +1,190 @@ +#define BOOST_TEST_MODULE bls +#include + +#include + + +#include +#include +#include +#include + +using std::cout; + +using namespace fc::crypto::blslib; + +BOOST_AUTO_TEST_SUITE(bls) + +// can we use BLS stuff? + +// Example seed, used to generate private key. Always use +// a secure RNG with sufficient entropy to generate a seed (at least 32 bytes). +std::vector seed_1 = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; + +std::vector seed_2 = { 6, 51, 22, 89, 11, 15, 4, 61, 127, 241, 79, + 26, 88, 52, 1, 6, 18, 79, 10, 8, 36, 182, + 154, 35, 75, 156, 215, 41, 29, 90, 125, 233}; + +std::vector message_1 = { 51, 23, 56, 93, 212, 129, 128, 27, + 251, 12, 42, 129, 210, 9, 34, 98}; // Message is passed in as a byte vector + + +std::vector message_2 = { 16, 38, 54, 125, 71, 214, 217, 78, + 73, 23, 127, 235, 8, 94, 41, 53}; // Message is passed in as a byte vector + + +//test a single key signature + verification +BOOST_AUTO_TEST_CASE(bls_sig_verif) try { + + bls_private_key sk = bls_private_key(seed_1); + bls_public_key pk = sk.get_public_key(); + + bls_signature signature = sk.sign(message_1); + + //cout << "pk : " << pk.to_string() << "\n"; + //cout << "signature : " << signature.to_string() << "\n"; + + // Verify the signature + bool ok = verify(pk, message_1, signature); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); + + +//test serialization / deserialization of private key, public key and signature +BOOST_AUTO_TEST_CASE(bls_serialization_test) try { + + bls_private_key sk = bls_private_key(seed_1); + bls_public_key pk = sk.get_public_key(); + + bls_signature signature = sk.sign(message_1); + + std::string pk_string = pk.to_string(); + std::string signature_string = signature.to_string(); + + //cout << pk_string << "\n"; + //cout << signature_string << "\n"; + + bls_public_key pk2 = bls_public_key(pk_string); + bls_signature signature2 = bls_signature(signature_string); + + //cout << pk2.to_string() << "\n"; + //cout << signature2.to_string() << "\n"; + + bool ok = verify(pk2, message_1, signature2); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); + +//test public keys + signatures aggregation + verification +BOOST_AUTO_TEST_CASE(bls_agg_sig_verif) try { + + bls_private_key sk1 = bls_private_key(seed_1); + bls_public_key pk1 = sk1.get_public_key(); + + bls_signature sig1 = sk1.sign(message_1); + + //cout << "pk1 : " << pk1.to_string() << "\n"; + //cout << "sig1 : " << sig1.to_string() << "\n"; + + bls_private_key sk2 = bls_private_key(seed_2); + bls_public_key pk2 = sk2.get_public_key(); + + bls_signature sig2 = sk2.sign(message_1); + + //cout << "pk2 : " << pk2.to_string() << "\n"; + //cout << "sig2 : " << sig2.to_string() << "\n"; + + bls_public_key aggKey = aggregate({pk1, pk2}); + bls_signature aggSig = aggregate({sig1, sig2}); + + // cout << "aggKey : " << aggKey.to_string() << "\n"; + //cout << "aggSig : " << aggSig.to_string() << "\n"; + + // Verify the signature + bool ok = verify(aggKey, message_1, aggSig); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); + + +//test signature aggregation + aggregate tree verification +BOOST_AUTO_TEST_CASE(bls_agg_tree_verif) try { + + bls_private_key sk1 = bls_private_key(seed_1); + bls_public_key pk1 = sk1.get_public_key(); + + bls_signature sig1 = sk1.sign(message_1); + + //cout << "pk1 : " << pk1.to_string() << "\n"; + //cout << "sig1 : " << sig1.to_string() << "\n"; + + bls_private_key sk2 = bls_private_key(seed_2); + bls_public_key pk2 = sk2.get_public_key(); + + bls_signature sig2 = sk2.sign(message_2); + + //cout << "pk2 : " << pk2.to_string() << "\n"; + //cout << "sig2 : " << sig2.to_string() << "\n"; + + bls_signature aggSig = aggregate({sig1, sig2}); + + //cout << "aggSig : " << aggSig.to_string() << "\n"; + + vector pubkeys = {pk1, pk2}; + vector> messages = {message_1, message_2}; + + // Verify the signature + bool ok = aggregate_verify(pubkeys, messages, aggSig); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); + + +//test random key generation, signature + verification +BOOST_AUTO_TEST_CASE(bls_key_gen) try { + + bls_private_key sk = generate(); + bls_public_key pk = sk.get_public_key(); + + bls_signature signature = sk.sign(message_1); + + // Verify the signature + bool ok = verify(pk, message_1, signature); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); + + +//test wrong key and wrong signature +BOOST_AUTO_TEST_CASE(bls_bad_sig_verif) try { + + bls_private_key sk1 = bls_private_key(seed_1); + bls_public_key pk1 = sk1.get_public_key(); + + bls_signature sig1 = sk1.sign(message_1); + + bls_private_key sk2 = bls_private_key(seed_2); + bls_public_key pk2 = sk2.get_public_key(); + + bls_signature sig2 = sk2.sign(message_1); + + // Verify the signature + bool ok1 = verify(pk1, message_1, sig2); //verify wrong key / signature + bool ok2 = verify(pk2, message_1, sig1); //verify wrong key / signature + + BOOST_CHECK_EQUAL(ok1, false); + BOOST_CHECK_EQUAL(ok2, false); + + +} FC_LOG_AND_RETHROW(); + + +BOOST_AUTO_TEST_SUITE_END() From 50fb0f978c8fbf63e609d28e6362c435d83435e7 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 11 Nov 2022 13:46:38 +0000 Subject: [PATCH 002/151] Initial hotstuff related structures --- .../chain/include/eosio/chain/hotstuff.hpp | 53 +++++++++++++++++++ .../include/eosio/net_plugin/protocol.hpp | 4 +- plugins/producer_plugin/producer_plugin.cpp | 18 +++++++ 3 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 libraries/chain/include/eosio/chain/hotstuff.hpp diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp new file mode 100644 index 0000000000..41766db171 --- /dev/null +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -0,0 +1,53 @@ +#pragma once +#include +#include + +namespace eosio { namespace chain { + + using bls_signature_type = fc::crypto::blslib::bls_signature; + + enum consensus_msg_type{ + new_view = 1, + prepare = 2, + pre_commit = 3, + commit = 4, + decide = 5 + }; + + struct consensus_node { + + uint32_t block_height; + fc::sha256 digest; + + }; + + struct quorum_certificate { + + consensus_msg_type msg_type; + uint32_t view_number; + consensus_node node; + + vector canonical_producers; + bls_signature_type sig; + + }; + + struct consensus_message { + + consensus_msg_type msg_type; + uint32_t view_number; + consensus_node node; + + quorum_certificate justify; + + }; + +}} + + +FC_REFLECT_ENUM( eosio::chain::consensus_msg_type, + (new_view)(prepare)(pre_commit)(commit)(decide) ); + +FC_REFLECT(eosio::chain::consensus_node, (block_height)(digest)); +FC_REFLECT(eosio::chain::quorum_certificate, (msg_type)(view_number)(node)(canonical_producers)(sig)); +FC_REFLECT(eosio::chain::consensus_message, (msg_type)(view_number)(node)(justify)); \ No newline at end of file diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index 2e7245c180..d66a9ca898 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include @@ -143,7 +144,8 @@ namespace eosio { request_message, sync_request_message, signed_block, // which = 7 - packed_transaction>; // which = 8 + packed_transaction, // which = 8 + consensus_message>; } // namespace eosio diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index a6d530070e..7a604a5d8b 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -270,6 +270,7 @@ class producer_plugin_impl : public std::enable_shared_from_this calculate_next_block_time(const account_name& producer_name, const block_timestamp_type& current_block_time) const; void schedule_production_loop(); + void schedule_hotstuff_loop(); void schedule_maybe_produce_block( bool exhausted ); void produce_block(); bool maybe_produce_block(); @@ -2328,11 +2329,16 @@ bool producer_plugin_impl::block_is_exhausted() const { void producer_plugin_impl::schedule_production_loop() { _timer.cancel(); + //ilog("loop"); + auto result = start_block(); _idle_trx_time = fc::time_point::now(); if (result == start_block_result::failed) { + + //ilog("block failed"); + elog("Failed to start a pending block, will try again later"); _timer.expires_from_now( boost::posix_time::microseconds( config::block_interval_us / 10 )); @@ -2345,6 +2351,9 @@ void producer_plugin_impl::schedule_production_loop() { } } ) ); } else if (result == start_block_result::waiting_for_block){ + + //ilog("waiting for block"); + if (!_producers.empty() && !production_disabled_by_policy()) { fc_dlog(_log, "Waiting till another block is received and scheduling Speculative/Production Change"); schedule_delayed_production_loop(weak_from_this(), calculate_producer_wake_up_time(calculate_pending_block_time())); @@ -2355,20 +2364,29 @@ void producer_plugin_impl::schedule_production_loop() { } else if (result == start_block_result::waiting_for_production) { // scheduled in start_block() + //ilog("waiting for production"); } else if (_pending_block_mode == pending_block_mode::producing) { + //ilog("producing"); + schedule_maybe_produce_block( result == start_block_result::exhausted ); } else if (_pending_block_mode == pending_block_mode::speculating && !_producers.empty() && !production_disabled_by_policy()){ + //ilog("speculative block created / sched spec/prod change "); chain::controller& chain = chain_plug->chain(); fc_dlog(_log, "Speculative Block Created; Scheduling Speculative/Production Change"); EOS_ASSERT( chain.is_building_block(), missing_pending_block_state, "speculating without pending_block_state" ); schedule_delayed_production_loop(weak_from_this(), calculate_producer_wake_up_time(chain.pending_block_time())); } else { fc_dlog(_log, "Speculative Block Created"); + // ilog("speculative block created"); } } +void producer_plugin_impl::schedule_hotstuff_loop() { + +} + void producer_plugin_impl::schedule_maybe_produce_block( bool exhausted ) { chain::controller& chain = chain_plug->chain(); From bda4ff3a935f174e0bed43ab35350689d596cdc2 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 23 Dec 2022 13:30:27 +0000 Subject: [PATCH 003/151] Instant Finality Prototype --- libraries/chain/controller.cpp | 18 ++ .../chain/include/eosio/chain/config.hpp | 1 + .../chain/include/eosio/chain/controller.hpp | 6 + .../chain/include/eosio/chain/hotstuff.hpp | 65 +++-- libraries/libfc/src/crypto/bls_utils.cpp | 12 - libraries/libfc/src/network/ntp.cpp | 265 ------------------ libraries/libfc/test/test_bls.cpp | 95 +++++++ .../include/eosio/net_plugin/protocol.hpp | 3 +- plugins/net_plugin/net_plugin.cpp | 203 +++++++++++++- plugins/producer_plugin/CMakeLists.txt | 1 + .../eosio/producer_plugin/producer_plugin.hpp | 4 + plugins/producer_plugin/producer_plugin.cpp | 43 ++- programs/nodeos/main.cpp | 4 + 13 files changed, 413 insertions(+), 307 deletions(-) delete mode 100644 libraries/libfc/src/crypto/bls_utils.cpp delete mode 100644 libraries/libfc/src/network/ntp.cpp diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 3316c13f18..bacea070d3 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1659,6 +1659,8 @@ struct controller_impl { { EOS_ASSERT( !pending, block_validate_exception, "pending block already exists" ); + //ilog("starting block... "); + emit( self.block_start, head->block_num + 1 ); if (auto dm_logger = get_deep_mind_logger()) { @@ -1932,6 +1934,14 @@ struct controller_impl { pending->push(); } + void commit_consensus_msg(consensus_message_ptr msg){ + emit( self.new_consensus_message, msg ); + } + + void commit_confirmation_msg(confirmation_message_ptr msg){ + emit( self.new_confirmation_message, msg ); + } + /** * 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 @@ -2889,6 +2899,14 @@ void controller::commit_block() { my->commit_block(true); } +void controller::commit_consensus_msg(consensus_message_ptr msg) { + my->commit_consensus_msg(msg); +} + +void controller::commit_confirmation_msg(confirmation_message_ptr msg) { + my->commit_confirmation_msg(msg); +} + deque controller::abort_block() { return my->abort_block(); } diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 9c45aaf849..096bc69f88 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -12,6 +12,7 @@ const static auto reversible_blocks_dir_name = "reversible"; const static auto default_state_dir_name = "state"; const static auto forkdb_filename = "fork_db.dat"; +const static auto qcdb_filename = "qc_db.dat"; const static auto default_state_size = 1*1024*1024*1024ll; const static auto default_state_guard_size = 128*1024*1024ll; diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index da6fe4c4d1..110c8a9c95 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -174,6 +175,9 @@ namespace eosio { namespace chain { block_state_ptr finalize_block( block_report& br, const signer_callback_type& signer_callback ); void sign_block( const signer_callback_type& signer_callback ); void commit_block(); + + void commit_consensus_msg(consensus_message_ptr msg); + void commit_confirmation_msg(confirmation_message_ptr msg); std::future create_block_state_future( const block_id_type& id, const signed_block_ptr& b ); @@ -334,6 +338,8 @@ namespace eosio { namespace chain { signal accepted_transaction; signal)> applied_transaction; signal bad_alloc; + signal new_consensus_message; + signal new_confirmation_message; /* signal pre_apply_block; diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 41766db171..5b7b14b38d 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -1,53 +1,74 @@ #pragma once -#include +#include #include namespace eosio { namespace chain { using bls_signature_type = fc::crypto::blslib::bls_signature; - enum consensus_msg_type{ - new_view = 1, - prepare = 2, - pre_commit = 3, - commit = 4, - decide = 5 + enum consensus_msg_type { + cm_new_view = 1, + cm_prepare = 2, + cm_pre_commit = 3, + cm_commit = 4, + cm_decide = 5 }; struct consensus_node { + + block_header header; + fc::sha256 previous_bmroot; + fc::sha256 schedule_hash; + fc::sha256 digest_to_sign; - uint32_t block_height; - fc::sha256 digest; + }; + + struct confirmation_message { + + consensus_msg_type msg_type; + uint32_t view_number; + consensus_node node; + + name finalizer; + bls_signature_type sig; + + confirmation_message() = default; }; struct quorum_certificate { - consensus_msg_type msg_type; - uint32_t view_number; - consensus_node node; + consensus_msg_type msg_type; + uint32_t view_number; + consensus_node node; - vector canonical_producers; - bls_signature_type sig; + vector finalizers; + bls_signature_type sig; }; struct consensus_message { - consensus_msg_type msg_type; - uint32_t view_number; - consensus_node node; + consensus_msg_type msg_type; + uint32_t view_number; + consensus_node node; - quorum_certificate justify; + std::optional justify; + consensus_message() = default; + }; -}} + using consensus_message_ptr = std::shared_ptr; + using confirmation_message_ptr = std::shared_ptr; + +}} //eosio::chain FC_REFLECT_ENUM( eosio::chain::consensus_msg_type, - (new_view)(prepare)(pre_commit)(commit)(decide) ); + (cm_new_view)(cm_prepare)(cm_pre_commit)(cm_commit)(cm_decide) ); -FC_REFLECT(eosio::chain::consensus_node, (block_height)(digest)); -FC_REFLECT(eosio::chain::quorum_certificate, (msg_type)(view_number)(node)(canonical_producers)(sig)); +FC_REFLECT(eosio::chain::consensus_node, (header)(previous_bmroot)(schedule_hash)(digest_to_sign)); +FC_REFLECT(eosio::chain::confirmation_message, (msg_type)(view_number)(node)(finalizer)(sig)); +FC_REFLECT(eosio::chain::quorum_certificate, (msg_type)(view_number)(node)(finalizers)(sig)); FC_REFLECT(eosio::chain::consensus_message, (msg_type)(view_number)(node)(justify)); \ No newline at end of file diff --git a/libraries/libfc/src/crypto/bls_utils.cpp b/libraries/libfc/src/crypto/bls_utils.cpp deleted file mode 100644 index 30aab8e3dd..0000000000 --- a/libraries/libfc/src/crypto/bls_utils.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -namespace fc { namespace crypto { namespace blslib { - - static bool verify( const blslib::bls_public_key &pubkey, - const vector &message, - const bls_signature &signature){ - - } - -} } } // fc::crypto::blslib diff --git a/libraries/libfc/src/network/ntp.cpp b/libraries/libfc/src/network/ntp.cpp deleted file mode 100644 index c73880278c..0000000000 --- a/libraries/libfc/src/network/ntp.cpp +++ /dev/null @@ -1,265 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include "../byteswap.hpp" - -#include -#include - -namespace fc -{ - namespace detail { - using boost::fibers::future; - - class ntp_impl - { - public: - /** vector < host, port > */ - fc::thread _ntp_thread; - std::vector< std::pair< std::string, uint16_t> > _ntp_hosts; - future _read_loop_done; - udp_socket _sock; - uint32_t _request_interval_sec; - uint32_t _retry_failed_request_interval_sec; - fc::time_point _last_valid_ntp_reply_received_time; - - std::atomic_bool _last_ntp_delta_initialized; - std::atomic _last_ntp_delta_microseconds; - - future _request_time_task_done; - - std::shared_ptr> _scheduled_request_time; - - ntp_impl() : - _ntp_thread("ntp"), - _request_interval_sec( 60*60 /* 1 hr */), - _retry_failed_request_interval_sec(60 * 5), - _last_ntp_delta_microseconds(0) - { - _last_ntp_delta_initialized = false; - _ntp_hosts.push_back( std::make_pair( "pool.ntp.org",123 ) ); - } - - ~ntp_impl() - { - _sock.close(); - if( _scheduled_request_time ) { - _scheduled_request_time->cancel(); - _scheduled_request_time->get_future().wait(); - _scheduled_request_time.reset(); - } - } - - fc::time_point ntp_timestamp_to_fc_time_point(uint64_t ntp_timestamp_net_order) - { - uint64_t ntp_timestamp_host = bswap_64(ntp_timestamp_net_order); - uint32_t fractional_seconds = ntp_timestamp_host & 0xffffffff; - uint32_t microseconds = (uint32_t)((((uint64_t)fractional_seconds * 1000000) + (uint64_t(1) << 31)) >> 32); - uint32_t seconds_since_1900 = ntp_timestamp_host >> 32; - uint32_t seconds_since_epoch = seconds_since_1900 - 2208988800; - return fc::time_point() + fc::seconds(seconds_since_epoch) + fc::microseconds(microseconds); - } - - uint64_t fc_time_point_to_ntp_timestamp(const fc::time_point& fc_timestamp) - { - uint64_t microseconds_since_epoch = (uint64_t)fc_timestamp.time_since_epoch().count(); - uint32_t seconds_since_epoch = (uint32_t)(microseconds_since_epoch / 1000000); - uint32_t seconds_since_1900 = seconds_since_epoch + 2208988800; - uint32_t microseconds = microseconds_since_epoch % 1000000; - uint32_t fractional_seconds = (uint32_t)((((uint64_t)microseconds << 32) + (uint64_t(1) << 31)) / 1000000); - uint64_t ntp_timestamp_net_order = ((uint64_t)seconds_since_1900 << 32) + fractional_seconds; - return bswap_64(ntp_timestamp_net_order); - } - - void request_now() - { - FC_ASSERT(_ntp_thread.is_current()); - for( auto item : _ntp_hosts ) - { - try - { - wlog( "resolving... ${r}", ("r", item) ); - auto eps = resolve( item.first, item.second ); - for( auto ep : eps ) - { - wlog( "sending request to ${ep}", ("ep",ep) ); - std::shared_ptr send_buffer(new char[48], [](char* p){ delete[] p; }); - std::array packet_to_send { {010,0,0,0,0,0,0,0,0} }; - memcpy(send_buffer.get(), packet_to_send.data(), packet_to_send.size()); - uint64_t* send_buf_as_64_array = (uint64_t*)send_buffer.get(); - send_buf_as_64_array[5] = fc_time_point_to_ntp_timestamp(fc::time_point::now()); // 5 = Transmit Timestamp - _sock.send_to(send_buffer, packet_to_send.size(), ep); - break; - } - } - catch (const fc::canceled_exception&) - { - throw; - } - catch ( const std::bad_alloc& ) - { - throw; - } - catch ( const boost::interprocess::bad_alloc& ) - { - throw; - } - // this could fail to resolve but we want to go on to other hosts.. - catch ( const fc::exception& e ) - { - elog( "${e}", ("e",e.to_detail_string() ) ); - } - catch ( const std::exception& e ) - { - elog( "${e}", ("e",e.what() ) ); - } - } - } // request_now - - // started for first time in ntp() constructor, canceled in ~ntp() destructor - // this task gets invoked every _retry_failed_request_interval_sec (currently 5 min), and if - // _request_interval_sec (currently 1 hour) has passed since the last successful update, - // it sends a new request - void request_time_task() - { - request_now(); - } // request_loop - - void start_read_loop() - { - _read_loop_done = _ntp_thread.async( [this](){ read_loop(); } ); - } - - void read_loop() - { - FC_ASSERT(_ntp_thread.is_current()); - - uint32_t receive_buffer_size = sizeof(uint64_t) * 1024; - std::shared_ptr receive_buffer(new char[receive_buffer_size], [](char* p){ delete[] p; }); - uint64_t* recv_buf = (uint64_t*)receive_buffer.get(); - - // if you start the read while loop here, the recieve_from call will throw "invalid argument" on win32, - // so instead we start the loop after making our first request - _sock.open(); - _request_time_task_done = fc::async( [&](){ request_time_task(); } ); - - while( true ) - { - fc::ip::endpoint from; - try - { - _sock.receive_from( receive_buffer, receive_buffer_size, from ); - // wlog("received ntp reply from ${from}",("from",from) ); - } FC_RETHROW_EXCEPTIONS(error, "Error reading from NTP socket"); - - fc::time_point receive_time = fc::time_point::now(); - fc::time_point origin_time = ntp_timestamp_to_fc_time_point(recv_buf[3]); - fc::time_point server_receive_time = ntp_timestamp_to_fc_time_point(recv_buf[4]); - fc::time_point server_transmit_time = ntp_timestamp_to_fc_time_point(recv_buf[5]); - - fc::microseconds offset(((server_receive_time - origin_time) + - (server_transmit_time - receive_time)).count() / 2); - fc::microseconds round_trip_delay((receive_time - origin_time) - - (server_transmit_time - server_receive_time)); - //wlog("origin_time = ${origin_time}, server_receive_time = ${server_receive_time}, server_transmit_time = ${server_transmit_time}, receive_time = ${receive_time}", - // ("origin_time", origin_time)("server_receive_time", server_receive_time)("server_transmit_time", server_transmit_time)("receive_time", receive_time)); - // wlog("ntp offset: ${offset}, round_trip_delay ${delay}", ("offset", offset)("delay", round_trip_delay)); - - //if the reply we just received has occurred more than a second after our last time request (it was more than a second ago since our last request) - if( round_trip_delay > fc::microseconds(300000) ) - { - wlog("received stale ntp reply requested at ${request_time}, send a new time request", ("request_time", origin_time)); - request_now(); //request another reply and ignore this one - } - else //we think we have a timely reply, process it - { - if( offset < fc::seconds(60*60*24) && offset > fc::seconds(-60*60*24) ) - { - _last_ntp_delta_microseconds = offset.count(); - _last_ntp_delta_initialized = true; - fc::microseconds ntp_delta_time = fc::microseconds(_last_ntp_delta_microseconds); - _last_valid_ntp_reply_received_time = receive_time; - wlog("ntp_delta_time updated to ${delta_time} us", ("delta_time",ntp_delta_time) ); - } - else - elog( "NTP time and local time vary by more than a day! ntp:${ntp_time} local:${local}", - ("ntp_time", receive_time + offset)("local", fc::time_point::now()) ); - } - } - wlog("exiting ntp read_loop"); - } //end read_loop() - - void reschedule() { - if( _scheduled_request_time ) - _scheduled_request_time->cancel(); - - _scheduled_request_time = _ntp_thread.schedule( - [&](){ - request_now(); - reschedule(); - }, - fc::time_point::now() + fc::seconds(_request_interval_sec) ); - } - }; //ntp_impl - - } // namespace detail - - - - ntp::ntp() - :my( new detail::ntp_impl() ) - { - my->start_read_loop(); - } - - ntp::~ntp() - { - ilog( "shutting down ntp" ); - my->_ntp_thread.async([=](){ - my->_sock.close(); - if( my->_scheduled_request_time ) { - ilog( "wait cancel scheduled request " ); - my->_scheduled_request_time->cancel(); - my->_scheduled_request_time->get_future().wait(); - my->_scheduled_request_time.reset(); - } - ilog( "wait request time task " ); - my->_request_time_task_done.wait(); - ilog( "wait read loop " ); - my->_read_loop_done.wait(); - }).wait(); - my->_ntp_thread.quit(); - ilog( "joining ntp" ); - my->_ntp_thread.join(); - } - - - void ntp::add_server( const std::string& hostname, uint16_t port) - { - my->_ntp_thread.async( [=](){ my->_ntp_hosts.push_back( std::make_pair(hostname,port) ); }).wait(); - } - - void ntp::set_request_interval( uint32_t interval_sec ) - { - my->_request_interval_sec = interval_sec; - my->_retry_failed_request_interval_sec = std::min(my->_retry_failed_request_interval_sec, interval_sec); - my->reschedule(); - } - - void ntp::request_now() - { - my->_ntp_thread.async( [=](){ my->request_now(); } ).get(); - } - - std::optional ntp::get_time()const - { - if( my->_last_ntp_delta_initialized ) - return fc::time_point::now() + fc::microseconds(my->_last_ntp_delta_microseconds); - return std::optional(); - } - -} //namespace fc diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index d568095f82..cb11635e5f 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -9,6 +9,8 @@ #include #include +#include + using std::cout; using namespace fc::crypto::blslib; @@ -34,6 +36,12 @@ std::vector message_1 = { 51, 23, 56, 93, 212, 129, 128, 27, std::vector message_2 = { 16, 38, 54, 125, 71, 214, 217, 78, 73, 23, 127, 235, 8, 94, 41, 53}; // Message is passed in as a byte vector +fc::sha256 message_3 = fc::sha256("1097cf48a15ba1c618237d3d79f3c684c031a9844c27e6b95c6d27d8a5f401a1"); + + +std::vector message_4 = {143,10,193,195,104,126,124,222,124,64,177,164,240,234,110,18,142,236,191,66,223,47,235,248,75,9,172,99,178,26,239,78}; + +bls_signature test_sig_single = bls_signature("SIG_BLS_23PuSu1B72cPe6wxGkKjAaaZqA1Ph79zSoW7omsKKUrnprbA3cJCJVhT48QKUG6ofjYTTg4BA4TrVENWyrxjTomwLX6TGdVg2RYhKH7Kk9X23K5ohuhKQcWQ6AwJJGVSbSp4"); //test a single key signature + verification BOOST_AUTO_TEST_CASE(bls_sig_verif) try { @@ -53,6 +61,93 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif) try { } FC_LOG_AND_RETHROW(); +//test a single key signature + verification of digest_type +BOOST_AUTO_TEST_CASE(bls_sig_verif_digest) try { + + bls_private_key sk = bls_private_key(seed_1); + bls_public_key pk = sk.get_public_key(); + + std::vector v = std::vector(message_3.data(), message_3.data() + 32); + + bls_signature signature = sk.sign(v); + + //cout << "pk : " << pk.to_string() << "\n"; + //cout << "signature : " << signature.to_string() << "\n"; + + // Verify the signature + bool ok = verify(pk, v, signature); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); + + +//test a single key signature + verification of hotstuff tuple +BOOST_AUTO_TEST_CASE(bls_sig_verif_hotstuff_types) try { + + bls_private_key sk = bls_private_key(seed_1); + bls_public_key pk = sk.get_public_key(); + + string cmt = "cm_prepare"; + uint32_t view_number = 264; + + string s_view_number = to_string(view_number); + string c_s = cmt + s_view_number; + + fc::sha256 h1 = fc::sha256::hash(c_s); + fc::sha256 h2 = fc::sha256::hash( std::make_pair( h1, message_3 ) ); + + std::vector v = std::vector(h2.data(), h2.data() + 32); + + bls_signature signature = sk.sign(v); + + bls_public_key agg_pk = pk; + bls_signature agg_signature = signature; + + for (int i = 1 ; i< 21 ;i++){ + agg_pk = aggregate({agg_pk, pk}); + agg_signature = aggregate({agg_signature, signature}); + } + + //cout << "pk : " << pk.to_string() << "\n"; + //cout << "signature : " << signature.to_string() << "\n"; + + // Verify the signature + bool ok = verify(agg_pk, v, agg_signature); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); + +//test a aggregate signature from string +BOOST_AUTO_TEST_CASE(bls_sig_verif_string_multi) try { + + bls_private_key sk = bls_private_key(seed_1); + + bls_public_key agg_key = sk.get_public_key(); + bls_signature agg_sig = test_sig_single; + + cout << 0 << "\n"; + cout << agg_key.to_string() << "\n"; + cout << agg_sig.to_string() << "\n"; + + for (int i = 1 ;i<14;i++){ + + agg_key = aggregate({agg_key, sk.get_public_key() }); + agg_sig = aggregate({agg_sig, test_sig_single}); + + cout << i << "\n"; + cout << agg_key.to_string() << "\n"; + cout << agg_sig.to_string() << "\n"; + + } + + bool ok = verify(agg_key, message_4, agg_sig); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); + //test serialization / deserialization of private key, public key and signature BOOST_AUTO_TEST_CASE(bls_serialization_test) try { diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index d66a9ca898..6ed0b18ea9 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -145,7 +145,8 @@ namespace eosio { sync_request_message, signed_block, // which = 7 packed_transaction, // which = 8 - consensus_message>; + confirmation_message, // which = 9 + consensus_message>; // which = 10 } // namespace eosio diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index f0bf1372d4..c054a3e343 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -193,6 +193,10 @@ namespace eosio { const time_point_sec& now = time_point::now() ); bool have_txn( const transaction_id_type& tid ) const; void expire_txns(); + + void bcast_consensus_msg(const consensus_message_ptr& msg); + void bcast_confirmation_msg(const confirmation_message_ptr& msg); + }; /** @@ -212,8 +216,11 @@ namespace eosio { constexpr auto def_keepalive_interval = 10000; constexpr auto message_header_size = sizeof(uint32_t); - constexpr uint32_t signed_block_which = fc::get_index(); // see protocol net_message - constexpr uint32_t packed_transaction_which = fc::get_index(); // see protocol net_message + + constexpr uint32_t signed_block_which = fc::get_index(); // see protocol net_message + constexpr uint32_t packed_transaction_which = fc::get_index(); // see protocol net_message + constexpr uint32_t confirmation_message_which = fc::get_index(); // see protocol net_message + constexpr uint32_t consensus_message_which = fc::get_index(); // see protocol net_message class net_plugin_impl : public std::enable_shared_from_this { public: @@ -307,6 +314,9 @@ namespace eosio { void transaction_ack(const std::pair&); void on_irreversible_block( const block_state_ptr& blk ); + void on_consensus_message( const consensus_message_ptr& msg ); + void on_confirmation_message( const confirmation_message_ptr& msg ); + void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_expire_timer(); void start_monitors(); @@ -687,6 +697,10 @@ namespace eosio { bool process_next_block_message(uint32_t message_length); bool process_next_trx_message(uint32_t message_length); + + bool process_next_consensus_message(uint32_t message_length); + bool process_next_confirmation_message(uint32_t message_length); + public: bool populate_handshake( handshake_message& hello ); @@ -784,6 +798,8 @@ namespace eosio { void handle_message( const block_id_type& id, signed_block_ptr msg ); void handle_message( const packed_transaction& msg ) = delete; // packed_transaction_ptr overload used instead void handle_message( packed_transaction_ptr msg ); + void handle_message( const confirmation_message_ptr& msg ); + void handle_message( const consensus_message_ptr& msg ); void process_signed_block( const block_id_type& id, signed_block_ptr msg ); @@ -854,6 +870,18 @@ namespace eosio { peer_dlog( c, "handle sync_request_message" ); c->handle_message( msg ); } + + void operator()( const confirmation_message_ptr& msg ) const { + // continue call to handle_message on connection strand + peer_dlog( c, "handle confirmation_message_ptr" ); + c->handle_message( msg ); + } + void operator()( const consensus_message_ptr& msg ) const { + // continue call to handle_message on connection strand + peer_dlog( c, "handle consensus_message_ptr" ); + c->handle_message( msg ); + } + }; template @@ -1388,6 +1416,42 @@ namespace eosio { } }; + struct consensus_message_buffer_factory : public buffer_factory { + + const send_buffer_type& get_send_buffer( const consensus_message_ptr& sb ) { + if( !send_buffer ) { + send_buffer = create_send_buffer( sb ); + } + return send_buffer; + } + + private: + + static std::shared_ptr> create_send_buffer( const consensus_message_ptr& sb ) { + static_assert( consensus_message_which == fc::get_index() ); + fc_dlog( logger, "sending consensus_message"); + return buffer_factory::create_send_buffer( consensus_message_which, *sb ); + } + }; + + struct confirmation_message_buffer_factory : public buffer_factory { + + const send_buffer_type& get_send_buffer( const confirmation_message_ptr& sb ) { + if( !send_buffer ) { + send_buffer = create_send_buffer( sb ); + } + return send_buffer; + } + + private: + + static std::shared_ptr> create_send_buffer( const confirmation_message_ptr& sb ) { + static_assert( confirmation_message_which == fc::get_index() ); + fc_dlog( logger, "sending confirmation_message"); + return buffer_factory::create_send_buffer( confirmation_message_which, *sb ); + } + }; + struct trx_buffer_factory : public buffer_factory { /// caches result for subsequent calls, only provide same packed_transaction_ptr instance for each invocation. @@ -2163,6 +2227,48 @@ namespace eosio { } ); } + void dispatch_manager::bcast_consensus_msg(const consensus_message_ptr& msg) { + if( my_impl->sync_master->syncing_with_peer() ) return; + + consensus_message_buffer_factory buff_factory; + + for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { + + if( !cp->current() ) return true; + send_buffer_type sb = buff_factory.get_send_buffer( msg ); + + cp->strand.post( [this, cp, sb{std::move(sb)}]() { + std::unique_lock g_conn( cp->conn_mtx ); + g_conn.unlock(); + + cp->enqueue_buffer( sb, no_reason ); + + }); + return true; + } ); + } + + void dispatch_manager::bcast_confirmation_msg(const confirmation_message_ptr& msg) { + if( my_impl->sync_master->syncing_with_peer() ) return; + + confirmation_message_buffer_factory buff_factory; + + for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { + + if( !cp->current() ) return true; + send_buffer_type sb = buff_factory.get_send_buffer( msg ); + + cp->strand.post( [this, cp, sb{std::move(sb)}]() { + std::unique_lock g_conn( cp->conn_mtx ); + g_conn.unlock(); + + cp->enqueue_buffer( sb, no_reason ); + + }); + return true; + } ); + } + // called from c's connection strand void dispatch_manager::recv_block(const connection_ptr& c, const block_id_type& id, uint32_t bnum) { std::unique_lock g( c->conn_mtx ); @@ -2580,7 +2686,16 @@ namespace eosio { } else if( which == packed_transaction_which ) { return process_next_trx_message( message_length ); + } else if( which == confirmation_message_which ) { + //ilog("process_next_message : process_next_confirmation_message"); + return process_next_confirmation_message( message_length ); + + } else if( which == consensus_message_which ) { + //ilog("process_next_message : process_next_consensus_message"); + return process_next_consensus_message( message_length ); + } else { + //ilog("process_next_message : other"); auto ds = pending_message_buffer.create_datastream(); net_message msg; fc::raw::unpack( ds, msg ); @@ -2596,6 +2711,44 @@ namespace eosio { return true; } + bool connection::process_next_confirmation_message(uint32_t message_length){ + + auto peek_ds = pending_message_buffer.create_peek_datastream(); + unsigned_int which{}; + fc::raw::unpack( peek_ds, which ); // throw away + + confirmation_message cm; + fc::raw::unpack( peek_ds, cm ); + + auto ds = pending_message_buffer.create_datastream(); + fc::raw::unpack( ds, which ); + shared_ptr ptr = std::make_shared(); + fc::raw::unpack( ds, *ptr ); + + handle_message(std::move( ptr ) ); + + return true; + } + + bool connection::process_next_consensus_message(uint32_t message_length){ + + auto peek_ds = pending_message_buffer.create_peek_datastream(); + unsigned_int which{}; + fc::raw::unpack( peek_ds, which ); // throw away + + consensus_message cm; + fc::raw::unpack( peek_ds, cm ); + + auto ds = pending_message_buffer.create_datastream(); + fc::raw::unpack( ds, which ); + shared_ptr ptr = std::make_shared(); + fc::raw::unpack( ds, *ptr ); + + handle_message(std::move( ptr ) ); + + return true; + } + // called from connection strand bool connection::process_next_block_message(uint32_t message_length) { auto peek_ds = pending_message_buffer.create_peek_datastream(); @@ -3111,6 +3264,26 @@ namespace eosio { } } + void connection::handle_message( const confirmation_message_ptr& msg ) { + //peer_ilog( this, "received confirmation message" ); + //ilog("received confirmation message"); + + if (my_impl->producer_plug != nullptr){ + my_impl->producer_plug->notify_confirmation_message(msg); + } + + } + + void connection::handle_message( const consensus_message_ptr& msg ) { + //peer_ilog( this, "received consensus message" ); + //ilog("received consensus message"); + + if (my_impl->producer_plug != nullptr){ + my_impl->producer_plug->notify_consensus_message(msg); + } + + } + size_t calc_trx_size( const packed_transaction_ptr& trx ) { return trx->get_estimated_size(); } @@ -3368,6 +3541,26 @@ namespace eosio { }); } + // called from application thread + void net_plugin_impl::on_consensus_message( const consensus_message_ptr& msg ){ + //ilog("network plugin received consensus message from application"); + + dispatcher->strand.post( [this, msg]() { + dispatcher->bcast_consensus_msg( msg ); + }); + + } + + // called from application thread + void net_plugin_impl::on_confirmation_message( const confirmation_message_ptr& msg ){ + //ilog("network plugin received confirmation message from application"); + + dispatcher->strand.post( [this, msg]() { + dispatcher->bcast_confirmation_msg( msg ); + }); + + } + // called from application thread void net_plugin_impl::on_pre_accepted_block(const signed_block_ptr& block) { update_chain_info(); @@ -3733,6 +3926,12 @@ namespace eosio { cc.irreversible_block.connect( [my = my]( const block_state_ptr& s ) { my->on_irreversible_block( s ); } ); + cc.new_consensus_message.connect( [my = my]( const consensus_message_ptr& s ) { + my->on_consensus_message( s ); + } ); + cc.new_confirmation_message.connect( [my = my]( const confirmation_message_ptr& s ) { + my->on_confirmation_message( s ); + } ); } { diff --git a/plugins/producer_plugin/CMakeLists.txt b/plugins/producer_plugin/CMakeLists.txt index a64518f7c9..159cd69291 100644 --- a/plugins/producer_plugin/CMakeLists.txt +++ b/plugins/producer_plugin/CMakeLists.txt @@ -2,6 +2,7 @@ file(GLOB HEADERS "include/eosio/producer_plugin/*.hpp") add_library( producer_plugin producer_plugin.cpp + qc_chain.cpp pending_snapshot.cpp ${HEADERS} ) diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index 2ee1f132f6..2c47c46029 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include @@ -110,6 +111,9 @@ class producer_plugin : public appbase::plugin { scheduled_protocol_feature_activations get_scheduled_protocol_feature_activations() const; void schedule_protocol_feature_activations(const scheduled_protocol_feature_activations& schedule); + void notify_confirmation_message( const chain::confirmation_message_ptr& msg); + void notify_consensus_message( const chain::consensus_message_ptr& msg ); + fc::variants get_supported_protocol_features( const get_supported_protocol_features_params& params ) const; get_account_ram_corrections_result get_account_ram_corrections( const get_account_ram_corrections_params& params ) const; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 7a604a5d8b..0a49842e39 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -27,6 +27,8 @@ #include #include +#include + namespace bmi = boost::multi_index; using bmi::indexed_by; using bmi::ordered_non_unique; @@ -270,8 +272,9 @@ class producer_plugin_impl : public std::enable_shared_from_this calculate_next_block_time(const account_name& producer_name, const block_timestamp_type& current_block_time) const; void schedule_production_loop(); - void schedule_hotstuff_loop(); void schedule_maybe_produce_block( bool exhausted ); + void notify_confirmation_message( const confirmation_message_ptr& msg); + void notify_consensus_message( const consensus_message_ptr& msg ); void produce_block(); bool maybe_produce_block(); bool block_is_exhausted() const; @@ -345,6 +348,7 @@ class producer_plugin_impl : public std::enable_shared_from_this _accepted_block_header_connection; std::optional _irreversible_block_connection; + qc_chain _qc_chain; /* * HACK ALERT * Boost timers can be in a state where a handler has not yet executed but is not abortable. @@ -382,6 +386,11 @@ class producer_plugin_impl : public std::enable_shared_from_thisblock_num % 120 == 0) _qc_chain.print_state(); + auto before = _unapplied_transactions.size(); _unapplied_transactions.clear_applied( bsp ); _subjective_billing.on_block( _log, bsp, fc::time_point::now() ); @@ -1003,6 +1012,8 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ } } + my->_qc_chain.init(my->chain_plug, my->_producers); + } FC_LOG_AND_RETHROW() } void producer_plugin::plugin_startup() @@ -1354,6 +1365,14 @@ void producer_plugin::schedule_protocol_feature_activations( const scheduled_pro my->_protocol_features_signaled = false; } +void producer_plugin::notify_confirmation_message( const confirmation_message_ptr& msg){ + my->notify_confirmation_message(msg); +}; + +void producer_plugin::notify_consensus_message( const consensus_message_ptr& msg ){ + my->notify_consensus_message(msg); +}; + fc::variants producer_plugin::get_supported_protocol_features( const get_supported_protocol_features_params& params ) const { fc::variants results; const chain::controller& chain = my->chain_plug->chain(); @@ -2383,10 +2402,6 @@ void producer_plugin_impl::schedule_production_loop() { } } -void producer_plugin_impl::schedule_hotstuff_loop() { - -} - void producer_plugin_impl::schedule_maybe_produce_block( bool exhausted ) { chain::controller& chain = chain_plug->chain(); @@ -2491,6 +2506,15 @@ static auto maybe_make_debug_time_logger() -> std::optionalactive_schedule.producers; + + //if we're producing after chain has activated, and we're not currently in the middle of a view + if (hbs->header.producer != name("eosio") && + (_qc_chain._qc_chain_state == qc_chain::qc_chain_state::initializing || _qc_chain._qc_chain_state == qc_chain::qc_chain_state::finished_view)){ + _qc_chain.create_new_view(*hbs); //we create a new view + } + br.total_time += fc::time_point::now() - start; ilog("Produced block ${id}... #${n} @ ${t} signed by ${p} " diff --git a/programs/nodeos/main.cpp b/programs/nodeos/main.cpp index b9cebe310a..8d05a5ff10 100644 --- a/programs/nodeos/main.cpp +++ b/programs/nodeos/main.cpp @@ -107,6 +107,9 @@ enum return_codes { int main(int argc, char** argv) { + + ilog("nodeos started"); + try { uint32_t short_hash = 0; fc::from_hex(eosio::version::version_hash(), (char*)&short_hash, sizeof(short_hash)); @@ -152,6 +155,7 @@ int main(int argc, char** argv) } catch( const node_management_success& e ) { return NODE_MANAGEMENT_SUCCESS; } catch( const fc::exception& e ) { + if( e.code() == fc::std_exception_code ) { if( e.top_message().find( "atabase dirty flag set" ) != std::string::npos ) { elog( "database dirty flag set (likely due to unclean shutdown): replay required" ); From 43ff8eafaaa4b08be56b688031d27435ef228804 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 30 Dec 2022 15:54:39 +0000 Subject: [PATCH 004/151] Implemented chained hotstuff core logic --- libraries/chain/controller.cpp | 32 +- .../chain/include/eosio/chain/controller.hpp | 13 +- .../chain/include/eosio/chain/hotstuff.hpp | 209 +++++++++--- .../libfc/include/fc/crypto/bls_signature.hpp | 1 + libraries/libfc/src/crypto/bls_signature.cpp | 5 +- .../include/eosio/net_plugin/protocol.hpp | 6 +- plugins/net_plugin/net_plugin.cpp | 298 ++++++++++++++---- .../eosio/producer_plugin/producer_plugin.hpp | 6 +- plugins/producer_plugin/producer_plugin.cpp | 58 ++-- 9 files changed, 499 insertions(+), 129 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index bacea070d3..24c2397b6f 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1934,12 +1934,20 @@ struct controller_impl { pending->push(); } - void commit_consensus_msg(consensus_message_ptr msg){ - emit( self.new_consensus_message, msg ); + void commit_hs_proposal_msg(hs_proposal_message_ptr msg){ + emit( self.new_hs_proposal_message, msg ); } - void commit_confirmation_msg(confirmation_message_ptr msg){ - emit( self.new_confirmation_message, msg ); + void commit_hs_vote_msg(hs_vote_message_ptr msg){ + emit( self.new_hs_vote_message, msg ); + } + + void commit_hs_new_view_msg(hs_new_view_message_ptr msg){ + emit( self.new_hs_new_view_message, msg ); + } + + void commit_hs_new_block_msg(hs_new_block_message_ptr msg){ + emit( self.new_hs_new_block_message, msg ); } /** @@ -2899,12 +2907,20 @@ void controller::commit_block() { my->commit_block(true); } -void controller::commit_consensus_msg(consensus_message_ptr msg) { - my->commit_consensus_msg(msg); +void controller::commit_hs_proposal_msg(hs_proposal_message_ptr msg) { + my->commit_hs_proposal_msg(msg); +} + +void controller::commit_hs_vote_msg(hs_vote_message_ptr msg) { + my->commit_hs_vote_msg(msg); +} + +void controller::commit_hs_new_view_msg(hs_new_view_message_ptr msg) { + my->commit_hs_new_view_msg(msg); } -void controller::commit_confirmation_msg(confirmation_message_ptr msg) { - my->commit_confirmation_msg(msg); +void controller::commit_hs_new_block_msg(hs_new_block_message_ptr msg) { + my->commit_hs_new_block_msg(msg); } deque controller::abort_block() { diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 110c8a9c95..6734437c41 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -176,8 +176,11 @@ namespace eosio { namespace chain { void sign_block( const signer_callback_type& signer_callback ); void commit_block(); - void commit_consensus_msg(consensus_message_ptr msg); - void commit_confirmation_msg(confirmation_message_ptr msg); + void commit_hs_proposal_msg(hs_proposal_message_ptr msg); + void commit_hs_vote_msg(hs_vote_message_ptr msg); + + void commit_hs_new_view_msg(hs_new_view_message_ptr msg); + void commit_hs_new_block_msg(hs_new_block_message_ptr msg); std::future create_block_state_future( const block_id_type& id, const signed_block_ptr& b ); @@ -338,8 +341,10 @@ namespace eosio { namespace chain { signal accepted_transaction; signal)> applied_transaction; signal bad_alloc; - signal new_consensus_message; - signal new_confirmation_message; + signal new_hs_proposal_message; + signal new_hs_vote_message; + signal new_hs_new_view_message; + signal new_hs_new_block_message; /* signal pre_apply_block; diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 5b7b14b38d..11062a0e1a 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -1,74 +1,205 @@ #pragma once #include +#include +#include #include +#include +#include +#include namespace eosio { namespace chain { - using bls_signature_type = fc::crypto::blslib::bls_signature; + //using namespace fc::crypto::blslib; + + //todo : fetch from chain / nodeos config + + const uint32_t block_interval = 500; + const uint32_t blocks_per_round = 12; + + const uint32_t _threshold = 15; + + static uint32_t compute_block_num(block_id_type block_id) + { + return fc::endian_reverse_u32(block_id._hash[0]); + } + + struct extended_schedule { + + producer_authority_schedule producer_schedule; + + std::map bls_pub_keys; - enum consensus_msg_type { - cm_new_view = 1, - cm_prepare = 2, - cm_pre_commit = 3, - cm_commit = 4, - cm_decide = 5 }; - struct consensus_node { +/* struct qc_height { + + uint32_t block_height; + uint8_t phase; + + bool operator == (const qc_height& rhs) { + if (block_height != rhs.block_height) return false; + if (phase != rhs.phase) return false; + return true; + } + + bool operator != (const qc_height& rhs) { + if (block_height != rhs.block_height) return true; + if (phase != rhs.phase) return true; + return false; + } + + bool operator<(const qc_height& rhs) { + if (block_height < rhs.block_height) return true; + else if (block_height == rhs.block_height){ + if (phase < rhs.phase) return true; + } + else return false; + } + + bool operator>(const qc_height& rhs) { + if (block_height > rhs.block_height) return true; + else if (block_height == rhs.block_height){ + if (phase > rhs.phase) return true; + } + else return false; + } + + };*/ + + struct quorum_certificate { + + public: + + block_id_type block_id; + + vector active_finalizers; + fc::crypto::blslib::bls_signature active_agg_sig; + + std::optional> incoming_finalizers; + std::optional incoming_agg_sig; + + uint32_t block_num()const{ + return compute_block_num(block_id); + } + + /*bool quorum_met(extended_schedule es, bool dual_set_mode){ + + if ( dual_set_mode && + incoming_finalizers.has_value() && + incoming_agg_sig.has_value()){ + return _quorum_met(es, active_finalizers, active_agg_sig) && _quorum_met(es, incoming_finalizers.value(), incoming_agg_sig.value()); + } + else { + return _quorum_met(es, active_finalizers, active_agg_sig); + } + + }; + + private: + bool _quorum_met(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig){ + + ilog("evaluating if _quorum_met"); + + if (finalizers.size() != _threshold){ + + ilog("finalizers.size() ${size}", ("size",finalizers.size())); + return false; + + } + + ilog("correct threshold"); + + fc::crypto::blslib::bls_public_key agg_key; + + for (name f : finalizers) { + + auto itr = es.bls_pub_keys.find(f); + + if (itr==es.bls_pub_keys.end()) return false; - block_header header; - fc::sha256 previous_bmroot; - fc::sha256 schedule_hash; - fc::sha256 digest_to_sign; + agg_key = fc::crypto::blslib::aggregate({agg_key, itr->second }); + + } + + std::vector msg = std::vector(block_id.data(), block_id.data() + 32); + + bool ok = fc::crypto::blslib::verify(agg_key, msg, agg_sig); + + return ok; + + return true; //temporary + + }*/ }; - struct confirmation_message { + struct hs_vote_message { + + block_id_type block_id; //vote on proposal - consensus_msg_type msg_type; - uint32_t view_number; - consensus_node node; + name finalizer; + fc::crypto::blslib::bls_signature sig; - name finalizer; - bls_signature_type sig; + hs_vote_message() = default; - confirmation_message() = default; + uint32_t block_num()const{ + return compute_block_num(block_id); + } }; - struct quorum_certificate { + struct hs_proposal_message { + + block_id_type block_id; //new proposal - consensus_msg_type msg_type; - uint32_t view_number; - consensus_node node; + std::optional justify; //justification - vector finalizers; - bls_signature_type sig; + hs_proposal_message() = default; + + uint32_t block_num()const{ + return compute_block_num(block_id); + } }; - struct consensus_message { + struct hs_new_block_message { + + block_id_type block_id; //new proposal + + std::optional justify; //justification - consensus_msg_type msg_type; - uint32_t view_number; - consensus_node node; + hs_new_block_message() = default; + + uint32_t block_num()const{ + return compute_block_num(block_id); + } + + }; - std::optional justify; + struct hs_new_view_message { - consensus_message() = default; + std::optional high_qc; //justification + + hs_new_view_message() = default; }; - using consensus_message_ptr = std::shared_ptr; - using confirmation_message_ptr = std::shared_ptr; + using hs_proposal_message_ptr = std::shared_ptr; + using hs_vote_message_ptr = std::shared_ptr; + using hs_new_view_message_ptr = std::shared_ptr; + using hs_new_block_message_ptr = std::shared_ptr; + }} //eosio::chain -FC_REFLECT_ENUM( eosio::chain::consensus_msg_type, - (cm_new_view)(cm_prepare)(cm_pre_commit)(cm_commit)(cm_decide) ); +//FC_REFLECT_ENUM( eosio::chain::consensus_msg_type, +// (cm_new_view)(cm_prepare)(cm_pre_commit)(cm_commit)(cm_decide) ); -FC_REFLECT(eosio::chain::consensus_node, (header)(previous_bmroot)(schedule_hash)(digest_to_sign)); -FC_REFLECT(eosio::chain::confirmation_message, (msg_type)(view_number)(node)(finalizer)(sig)); -FC_REFLECT(eosio::chain::quorum_certificate, (msg_type)(view_number)(node)(finalizers)(sig)); -FC_REFLECT(eosio::chain::consensus_message, (msg_type)(view_number)(node)(justify)); \ No newline at end of file +//FC_REFLECT(eosio::chain::consensus_node, (header)(previous_bmroot)(schedule_hash)(digest_to_sign)); +FC_REFLECT(eosio::chain::quorum_certificate, (block_id)(active_finalizers)(active_agg_sig)(incoming_finalizers)(incoming_agg_sig)); +//FC_REFLECT(eosio::chain::proposal, (block)(justify)); +FC_REFLECT(eosio::chain::hs_vote_message, (block_id)(finalizer)(sig)); +FC_REFLECT(eosio::chain::hs_proposal_message, (block_id)(justify)); +FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify)); +FC_REFLECT(eosio::chain::hs_new_view_message, (high_qc)); \ No newline at end of file diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index 0bf0c6c4a3..babb3dffb0 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -58,6 +58,7 @@ namespace fc { namespace crypto { namespace blslib { //friend bool operator != ( const bls_signature& p1, const bls_signature& p2); //friend bool operator < ( const bls_signature& p1, const bls_signature& p2); friend std::size_t hash_value(const bls_signature& b); //not cryptographic; for containers + friend bool operator == ( const bls_signature& p1, const bls_signature& p2); friend struct reflector; friend class bls_private_key; friend class bls_public_key; diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 83c54bed8d..78c82de1d1 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -74,11 +74,12 @@ namespace fc { namespace crypto { namespace blslib { s << "bls_signature(" << k.to_string() << ')'; return s; } -/* + bool operator == ( const bls_signature& p1, const bls_signature& p2) { - return eq_comparator::apply(p1._storage, p2._storage); + return p1._sig == p2._sig; } +/* bool operator != ( const bls_signature& p1, const bls_signature& p2) { return !eq_comparator::apply(p1._storage, p2._storage); } diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index 6ed0b18ea9..c645209950 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -145,8 +145,10 @@ namespace eosio { sync_request_message, signed_block, // which = 7 packed_transaction, // which = 8 - confirmation_message, // which = 9 - consensus_message>; // which = 10 + hs_vote_message, // hotstuff vote message, which = 9 + hs_proposal_message, // hotstuff proposal message, which = 10 + hs_new_view_message, // hotstuff proposal message, which = 11 + hs_new_block_message>; // hotstuff new block message, which = 12 } // namespace eosio diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index c054a3e343..181c207037 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -194,8 +194,10 @@ namespace eosio { bool have_txn( const transaction_id_type& tid ) const; void expire_txns(); - void bcast_consensus_msg(const consensus_message_ptr& msg); - void bcast_confirmation_msg(const confirmation_message_ptr& msg); + void bcast_hs_proposal_msg(const hs_proposal_message_ptr& msg); + void bcast_hs_vote_msg(const hs_vote_message_ptr& msg); + void bcast_hs_new_view_msg(const hs_new_view_message_ptr& msg); + void bcast_hs_new_block_msg(const hs_new_block_message_ptr& msg); }; @@ -219,8 +221,10 @@ namespace eosio { constexpr uint32_t signed_block_which = fc::get_index(); // see protocol net_message constexpr uint32_t packed_transaction_which = fc::get_index(); // see protocol net_message - constexpr uint32_t confirmation_message_which = fc::get_index(); // see protocol net_message - constexpr uint32_t consensus_message_which = fc::get_index(); // see protocol net_message + constexpr uint32_t hs_vote_message_which = fc::get_index(); // see protocol net_message + constexpr uint32_t hs_proposal_message_which = fc::get_index(); // see protocol net_message + constexpr uint32_t hs_new_view_message_which = fc::get_index(); // see protocol net_message + constexpr uint32_t hs_new_block_message_which = fc::get_index(); // see protocol net_message class net_plugin_impl : public std::enable_shared_from_this { public: @@ -314,8 +318,10 @@ namespace eosio { void transaction_ack(const std::pair&); void on_irreversible_block( const block_state_ptr& blk ); - void on_consensus_message( const consensus_message_ptr& msg ); - void on_confirmation_message( const confirmation_message_ptr& msg ); + void on_hs_proposal_message( const hs_proposal_message_ptr& msg ); + void on_hs_vote_message( const hs_vote_message_ptr& msg ); + void on_hs_new_view_message( const hs_new_view_message_ptr& msg ); + void on_hs_new_block_message( const hs_new_block_message_ptr& msg ); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_expire_timer(); @@ -698,8 +704,10 @@ namespace eosio { bool process_next_block_message(uint32_t message_length); bool process_next_trx_message(uint32_t message_length); - bool process_next_consensus_message(uint32_t message_length); - bool process_next_confirmation_message(uint32_t message_length); + bool process_next_hs_proposal_message(uint32_t message_length); + bool process_next_hs_vote_message(uint32_t message_length); + bool process_next_hs_new_view_message(uint32_t message_length); + bool process_next_hs_new_block_message(uint32_t message_length); public: @@ -798,8 +806,11 @@ namespace eosio { void handle_message( const block_id_type& id, signed_block_ptr msg ); void handle_message( const packed_transaction& msg ) = delete; // packed_transaction_ptr overload used instead void handle_message( packed_transaction_ptr msg ); - void handle_message( const confirmation_message_ptr& msg ); - void handle_message( const consensus_message_ptr& msg ); + void handle_message( const hs_vote_message_ptr& msg ); + void handle_message( const hs_proposal_message_ptr& msg ); + void handle_message( const hs_new_view_message_ptr& msg ); + void handle_message( const hs_new_block_message_ptr& msg ); + void process_signed_block( const block_id_type& id, signed_block_ptr msg ); @@ -871,14 +882,25 @@ namespace eosio { c->handle_message( msg ); } - void operator()( const confirmation_message_ptr& msg ) const { + void operator()( const hs_vote_message_ptr& msg ) const { // continue call to handle_message on connection strand - peer_dlog( c, "handle confirmation_message_ptr" ); + peer_dlog( c, "handle hs_vote_message_ptr" ); c->handle_message( msg ); } - void operator()( const consensus_message_ptr& msg ) const { + void operator()( const hs_proposal_message_ptr& msg ) const { // continue call to handle_message on connection strand - peer_dlog( c, "handle consensus_message_ptr" ); + peer_dlog( c, "handle hs_proposal_message_ptr" ); + c->handle_message( msg ); + } + + void operator()( const hs_new_view_message_ptr& msg ) const { + // continue call to handle_message on connection strand + peer_dlog( c, "handle hs_new_view_message_ptr" ); + c->handle_message( msg ); + } + void operator()( const hs_new_block_message_ptr& msg ) const { + // continue call to handle_message on connection strand + peer_dlog( c, "handle hs_new_block_message_ptr" ); c->handle_message( msg ); } @@ -1416,9 +1438,9 @@ namespace eosio { } }; - struct consensus_message_buffer_factory : public buffer_factory { + struct hs_proposal_message_buffer_factory : public buffer_factory { - const send_buffer_type& get_send_buffer( const consensus_message_ptr& sb ) { + const send_buffer_type& get_send_buffer( const hs_proposal_message_ptr& sb ) { if( !send_buffer ) { send_buffer = create_send_buffer( sb ); } @@ -1427,16 +1449,16 @@ namespace eosio { private: - static std::shared_ptr> create_send_buffer( const consensus_message_ptr& sb ) { - static_assert( consensus_message_which == fc::get_index() ); - fc_dlog( logger, "sending consensus_message"); - return buffer_factory::create_send_buffer( consensus_message_which, *sb ); + static std::shared_ptr> create_send_buffer( const hs_proposal_message_ptr& sb ) { + static_assert( hs_proposal_message_which == fc::get_index() ); + fc_dlog( logger, "sending hs_proposal_message"); + return buffer_factory::create_send_buffer( hs_proposal_message_which, *sb ); } }; - struct confirmation_message_buffer_factory : public buffer_factory { + struct hs_vote_message_buffer_factory : public buffer_factory { - const send_buffer_type& get_send_buffer( const confirmation_message_ptr& sb ) { + const send_buffer_type& get_send_buffer( const hs_vote_message_ptr& sb ) { if( !send_buffer ) { send_buffer = create_send_buffer( sb ); } @@ -1445,13 +1467,48 @@ namespace eosio { private: - static std::shared_ptr> create_send_buffer( const confirmation_message_ptr& sb ) { - static_assert( confirmation_message_which == fc::get_index() ); - fc_dlog( logger, "sending confirmation_message"); - return buffer_factory::create_send_buffer( confirmation_message_which, *sb ); + static std::shared_ptr> create_send_buffer( const hs_vote_message_ptr& sb ) { + static_assert( hs_vote_message_which == fc::get_index() ); + fc_dlog( logger, "sending hs_vote_message"); + return buffer_factory::create_send_buffer( hs_vote_message_which, *sb ); } }; + struct hs_new_view_message_buffer_factory : public buffer_factory { + + const send_buffer_type& get_send_buffer( const hs_new_view_message_ptr& sb ) { + if( !send_buffer ) { + send_buffer = create_send_buffer( sb ); + } + return send_buffer; + } + + private: + + static std::shared_ptr> create_send_buffer( const hs_new_view_message_ptr& sb ) { + static_assert( hs_new_view_message_which == fc::get_index() ); + fc_dlog( logger, "sending hs_new_view_message"); + return buffer_factory::create_send_buffer( hs_new_view_message_which, *sb ); + } + }; + + struct hs_new_block_message_buffer_factory : public buffer_factory { + + const send_buffer_type& get_send_buffer( const hs_new_block_message_ptr& sb ) { + if( !send_buffer ) { + send_buffer = create_send_buffer( sb ); + } + return send_buffer; + } + + private: + + static std::shared_ptr> create_send_buffer( const hs_new_block_message_ptr& sb ) { + static_assert( hs_new_block_message_which == fc::get_index() ); + fc_dlog( logger, "sending hs_new_block_message"); + return buffer_factory::create_send_buffer( hs_new_block_message_which, *sb ); + } + }; struct trx_buffer_factory : public buffer_factory { /// caches result for subsequent calls, only provide same packed_transaction_ptr instance for each invocation. @@ -2227,10 +2284,52 @@ namespace eosio { } ); } - void dispatch_manager::bcast_consensus_msg(const consensus_message_ptr& msg) { + void dispatch_manager::bcast_hs_proposal_msg(const hs_proposal_message_ptr& msg) { + if( my_impl->sync_master->syncing_with_peer() ) return; + + hs_proposal_message_buffer_factory buff_factory; + + for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { + + if( !cp->current() ) return true; + send_buffer_type sb = buff_factory.get_send_buffer( msg ); + + cp->strand.post( [this, cp, sb{std::move(sb)}]() { + std::unique_lock g_conn( cp->conn_mtx ); + g_conn.unlock(); + + cp->enqueue_buffer( sb, no_reason ); + + }); + return true; + } ); + } + + void dispatch_manager::bcast_hs_vote_msg(const hs_vote_message_ptr& msg) { + if( my_impl->sync_master->syncing_with_peer() ) return; + + hs_vote_message_buffer_factory buff_factory; + + for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { + + if( !cp->current() ) return true; + send_buffer_type sb = buff_factory.get_send_buffer( msg ); + + cp->strand.post( [this, cp, sb{std::move(sb)}]() { + std::unique_lock g_conn( cp->conn_mtx ); + g_conn.unlock(); + + cp->enqueue_buffer( sb, no_reason ); + + }); + return true; + } ); + } + + void dispatch_manager::bcast_hs_new_block_msg(const hs_new_block_message_ptr& msg) { if( my_impl->sync_master->syncing_with_peer() ) return; - consensus_message_buffer_factory buff_factory; + hs_new_block_message_buffer_factory buff_factory; for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { @@ -2248,10 +2347,10 @@ namespace eosio { } ); } - void dispatch_manager::bcast_confirmation_msg(const confirmation_message_ptr& msg) { + void dispatch_manager::bcast_hs_new_view_msg(const hs_new_view_message_ptr& msg) { if( my_impl->sync_master->syncing_with_peer() ) return; - confirmation_message_buffer_factory buff_factory; + hs_new_view_message_buffer_factory buff_factory; for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { @@ -2686,13 +2785,21 @@ namespace eosio { } else if( which == packed_transaction_which ) { return process_next_trx_message( message_length ); - } else if( which == confirmation_message_which ) { - //ilog("process_next_message : process_next_confirmation_message"); - return process_next_confirmation_message( message_length ); + } else if( which == hs_vote_message_which ) { + //ilog("process_next_message : process_next_hs_vote_message"); + return process_next_hs_vote_message( message_length ); + + } else if( which == hs_proposal_message_which ) { + //ilog("process_next_message : process_next_hs_proposal_message"); + return process_next_hs_proposal_message( message_length ); - } else if( which == consensus_message_which ) { - //ilog("process_next_message : process_next_consensus_message"); - return process_next_consensus_message( message_length ); + } else if( which == hs_new_view_message_which ) { + //ilog("process_next_message : process_next_hs_new_view_message"); + return process_next_hs_new_view_message( message_length ); + + } else if( which == hs_new_block_message_which ) { + //ilog("process_next_message : process_next_hs_new_block_message"); + return process_next_hs_new_block_message( message_length ); } else { //ilog("process_next_message : other"); @@ -2711,18 +2818,18 @@ namespace eosio { return true; } - bool connection::process_next_confirmation_message(uint32_t message_length){ + bool connection::process_next_hs_vote_message(uint32_t message_length){ auto peek_ds = pending_message_buffer.create_peek_datastream(); unsigned_int which{}; fc::raw::unpack( peek_ds, which ); // throw away - confirmation_message cm; + hs_vote_message cm; fc::raw::unpack( peek_ds, cm ); auto ds = pending_message_buffer.create_datastream(); fc::raw::unpack( ds, which ); - shared_ptr ptr = std::make_shared(); + shared_ptr ptr = std::make_shared(); fc::raw::unpack( ds, *ptr ); handle_message(std::move( ptr ) ); @@ -2730,18 +2837,56 @@ namespace eosio { return true; } - bool connection::process_next_consensus_message(uint32_t message_length){ + bool connection::process_next_hs_proposal_message(uint32_t message_length){ auto peek_ds = pending_message_buffer.create_peek_datastream(); unsigned_int which{}; fc::raw::unpack( peek_ds, which ); // throw away - consensus_message cm; + hs_proposal_message cm; fc::raw::unpack( peek_ds, cm ); auto ds = pending_message_buffer.create_datastream(); fc::raw::unpack( ds, which ); - shared_ptr ptr = std::make_shared(); + shared_ptr ptr = std::make_shared(); + fc::raw::unpack( ds, *ptr ); + + handle_message(std::move( ptr ) ); + + return true; + } + + bool connection::process_next_hs_new_view_message(uint32_t message_length){ + + auto peek_ds = pending_message_buffer.create_peek_datastream(); + unsigned_int which{}; + fc::raw::unpack( peek_ds, which ); // throw away + + hs_new_view_message cm; + fc::raw::unpack( peek_ds, cm ); + + auto ds = pending_message_buffer.create_datastream(); + fc::raw::unpack( ds, which ); + shared_ptr ptr = std::make_shared(); + fc::raw::unpack( ds, *ptr ); + + handle_message(std::move( ptr ) ); + + return true; + } + + bool connection::process_next_hs_new_block_message(uint32_t message_length){ + + auto peek_ds = pending_message_buffer.create_peek_datastream(); + unsigned_int which{}; + fc::raw::unpack( peek_ds, which ); // throw away + + hs_new_block_message cm; + fc::raw::unpack( peek_ds, cm ); + + auto ds = pending_message_buffer.create_datastream(); + fc::raw::unpack( ds, which ); + shared_ptr ptr = std::make_shared(); fc::raw::unpack( ds, *ptr ); handle_message(std::move( ptr ) ); @@ -3264,26 +3409,45 @@ namespace eosio { } } - void connection::handle_message( const confirmation_message_ptr& msg ) { + void connection::handle_message( const hs_vote_message_ptr& msg ) { //peer_ilog( this, "received confirmation message" ); //ilog("received confirmation message"); if (my_impl->producer_plug != nullptr){ - my_impl->producer_plug->notify_confirmation_message(msg); + my_impl->producer_plug->notify_hs_vote_message(msg); } } - void connection::handle_message( const consensus_message_ptr& msg ) { + void connection::handle_message( const hs_proposal_message_ptr& msg ) { //peer_ilog( this, "received consensus message" ); //ilog("received consensus message"); if (my_impl->producer_plug != nullptr){ - my_impl->producer_plug->notify_consensus_message(msg); + my_impl->producer_plug->notify_hs_proposal_message(msg); + } + + } + + void connection::handle_message( const hs_new_view_message_ptr& msg ) { + //peer_ilog( this, "received new view message" ); + //ilog("received new view message"); + + if (my_impl->producer_plug != nullptr){ + my_impl->producer_plug->notify_hs_new_view_message(msg); } } + void connection::handle_message( const hs_new_block_message_ptr& msg ) { + //peer_ilog( this, "received new block message" ); + //ilog("received new block message"); + + if (my_impl->producer_plug != nullptr){ + my_impl->producer_plug->notify_hs_new_block_message(msg); + } + + } size_t calc_trx_size( const packed_transaction_ptr& trx ) { return trx->get_estimated_size(); } @@ -3542,21 +3706,41 @@ namespace eosio { } // called from application thread - void net_plugin_impl::on_consensus_message( const consensus_message_ptr& msg ){ + void net_plugin_impl::on_hs_proposal_message( const hs_proposal_message_ptr& msg ){ //ilog("network plugin received consensus message from application"); dispatcher->strand.post( [this, msg]() { - dispatcher->bcast_consensus_msg( msg ); + dispatcher->bcast_hs_proposal_msg( msg ); }); } // called from application thread - void net_plugin_impl::on_confirmation_message( const confirmation_message_ptr& msg ){ + void net_plugin_impl::on_hs_vote_message( const hs_vote_message_ptr& msg ){ //ilog("network plugin received confirmation message from application"); dispatcher->strand.post( [this, msg]() { - dispatcher->bcast_confirmation_msg( msg ); + dispatcher->bcast_hs_vote_msg( msg ); + }); + + } + + // called from application thread + void net_plugin_impl::on_hs_new_view_message( const hs_new_view_message_ptr& msg ){ + //ilog("network plugin received new_view message from application"); + + dispatcher->strand.post( [this, msg]() { + dispatcher->bcast_hs_new_view_msg( msg ); + }); + + } + + // called from application thread + void net_plugin_impl::on_hs_new_block_message( const hs_new_block_message_ptr& msg ){ + //ilog("network plugin received new_block message from application"); + + dispatcher->strand.post( [this, msg]() { + dispatcher->bcast_hs_new_block_msg( msg ); }); } @@ -3926,11 +4110,17 @@ namespace eosio { cc.irreversible_block.connect( [my = my]( const block_state_ptr& s ) { my->on_irreversible_block( s ); } ); - cc.new_consensus_message.connect( [my = my]( const consensus_message_ptr& s ) { - my->on_consensus_message( s ); + cc.new_hs_proposal_message.connect( [my = my]( const hs_proposal_message_ptr& s ) { + my->on_hs_proposal_message( s ); + } ); + cc.new_hs_vote_message.connect( [my = my]( const hs_vote_message_ptr& s ) { + my->on_hs_vote_message( s ); + } ); + cc.new_hs_new_view_message.connect( [my = my]( const hs_new_view_message_ptr& s ) { + my->on_hs_new_view_message( s ); } ); - cc.new_confirmation_message.connect( [my = my]( const confirmation_message_ptr& s ) { - my->on_confirmation_message( s ); + cc.new_hs_new_block_message.connect( [my = my]( const hs_new_block_message_ptr& s ) { + my->on_hs_new_block_message( s ); } ); } diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index 2c47c46029..0656c87f68 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -111,8 +111,10 @@ class producer_plugin : public appbase::plugin { scheduled_protocol_feature_activations get_scheduled_protocol_feature_activations() const; void schedule_protocol_feature_activations(const scheduled_protocol_feature_activations& schedule); - void notify_confirmation_message( const chain::confirmation_message_ptr& msg); - void notify_consensus_message( const chain::consensus_message_ptr& msg ); + void notify_hs_vote_message( const chain::hs_vote_message_ptr& msg); + void notify_hs_proposal_message( const chain::hs_proposal_message_ptr& msg ); + void notify_hs_new_view_message( const chain::hs_new_view_message_ptr& msg); + void notify_hs_new_block_message( const chain::hs_new_block_message_ptr& msg ); fc::variants get_supported_protocol_features( const get_supported_protocol_features_params& params ) const; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 0a49842e39..4a8a547832 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -273,8 +273,10 @@ class producer_plugin_impl : public std::enable_shared_from_this calculate_next_block_time(const account_name& producer_name, const block_timestamp_type& current_block_time) const; void schedule_production_loop(); void schedule_maybe_produce_block( bool exhausted ); - void notify_confirmation_message( const confirmation_message_ptr& msg); - void notify_consensus_message( const consensus_message_ptr& msg ); + void notify_hs_vote_message( const hs_vote_message_ptr& msg); + void notify_hs_proposal_message( const hs_proposal_message_ptr& msg ); + void notify_hs_new_view_message( const hs_new_view_message_ptr& msg); + void notify_hs_new_block_message( const hs_new_block_message_ptr& msg ); void produce_block(); bool maybe_produce_block(); bool block_is_exhausted() const; @@ -349,6 +351,7 @@ class producer_plugin_impl : public std::enable_shared_from_this _irreversible_block_connection; qc_chain _qc_chain; + /* * HACK ALERT * Boost timers can be in a state where a handler has not yet executed but is not abortable. @@ -389,7 +392,7 @@ class producer_plugin_impl : public std::enable_shared_from_thisblock_num % 120 == 0) _qc_chain.print_state(); + //if (bsp->block_num % 120 == 0) _qc_chain.print_state(); auto before = _unapplied_transactions.size(); _unapplied_transactions.clear_applied( bsp ); @@ -1012,7 +1015,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ } } - my->_qc_chain.init(my->chain_plug, my->_producers); + my->_qc_chain.init(*my->chain_plug, my->_producers); } FC_LOG_AND_RETHROW() } @@ -1365,12 +1368,20 @@ void producer_plugin::schedule_protocol_feature_activations( const scheduled_pro my->_protocol_features_signaled = false; } -void producer_plugin::notify_confirmation_message( const confirmation_message_ptr& msg){ - my->notify_confirmation_message(msg); +void producer_plugin::notify_hs_vote_message( const hs_vote_message_ptr& msg){ + my->notify_hs_vote_message(msg); +}; + +void producer_plugin::notify_hs_proposal_message( const hs_proposal_message_ptr& msg ){ + my->notify_hs_proposal_message(msg); }; -void producer_plugin::notify_consensus_message( const consensus_message_ptr& msg ){ - my->notify_consensus_message(msg); +void producer_plugin::notify_hs_new_view_message( const hs_new_view_message_ptr& msg){ + my->notify_hs_new_view_message(msg); +}; + +void producer_plugin::notify_hs_new_block_message( const hs_new_block_message_ptr& msg ){ + my->notify_hs_new_block_message(msg); }; fc::variants producer_plugin::get_supported_protocol_features( const get_supported_protocol_features_params& params ) const { @@ -2507,14 +2518,23 @@ static auto maybe_make_debug_time_logger() -> std::optionalactive_schedule.producers; - +*/ //if we're producing after chain has activated, and we're not currently in the middle of a view - if (hbs->header.producer != name("eosio") && - (_qc_chain._qc_chain_state == qc_chain::qc_chain_state::initializing || _qc_chain._qc_chain_state == qc_chain::qc_chain_state::finished_view)){ - _qc_chain.create_new_view(*hbs); //we create a new view - } + //if (hbs->header.producer != name("eosio") && + // (_qc_chain._qc_chain_state == qc_chain::qc_chain_state::initializing || _qc_chain._qc_chain_state == qc_chain::qc_chain_state::finished_view)){ + // _qc_chain.create_new_view(*hbs); //we create a new view + //} + + _qc_chain.on_beat(*new_bs); br.total_time += fc::time_point::now() - start; From 960415b036e5493862e18e583294a143eea107d1 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 30 Dec 2022 15:54:43 +0000 Subject: [PATCH 005/151] Implemented chained hotstuff core logic --- .../chain/include/eosio/chain/qc_database.hpp | 89 ++ libraries/chain/qc_database.cpp | 492 ++++++ libraries/libfc/src/crypto/bls_utils.cpp.old | 12 + .../eosio/producer_plugin/qc_chain.hpp | 145 ++ plugins/producer_plugin/qc_chain.cpp | 1355 +++++++++++++++++ plugins/producer_plugin/qc_chain.old.cpp | 573 +++++++ 6 files changed, 2666 insertions(+) create mode 100644 libraries/chain/include/eosio/chain/qc_database.hpp create mode 100644 libraries/chain/qc_database.cpp create mode 100644 libraries/libfc/src/crypto/bls_utils.cpp.old create mode 100644 plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp create mode 100644 plugins/producer_plugin/qc_chain.cpp create mode 100644 plugins/producer_plugin/qc_chain.old.cpp diff --git a/libraries/chain/include/eosio/chain/qc_database.hpp b/libraries/chain/include/eosio/chain/qc_database.hpp new file mode 100644 index 0000000000..a0d73fc1dc --- /dev/null +++ b/libraries/chain/include/eosio/chain/qc_database.hpp @@ -0,0 +1,89 @@ +#pragma once +#include +#include +#include + +namespace eosio { namespace chain { + + using boost::signals2::signal; + + struct qc_database_impl; + + class qc_database { + public: + + explicit qc_database( const fc::path& data_dir ); + ~qc_database(); + + void open( const std::function&, + const vector& )>& validator ); + void close(); + + //block_header_state_ptr get_block_header( const block_id_type& id )const; + //block_state_ptr get_block( const block_id_type& id )const; + + /** + * Purges any existing blocks from the fork database and resets the root block_header_state to the provided value. + * The head will also be reset to point to the root. + */ + //void reset( const block_header_state& root_bhs ); + + /** + * Removes validated flag from all blocks in fork database and resets head to point to the root. + */ + //void rollback_head_to_root(); + + /** + * Advance root block forward to some other block in the tree. + */ + //void advance_root( const block_id_type& id ); + + /** + * Add block state to fork database. + * Must link to existing block in fork database or the root. + */ + //void add( const block_state_ptr& next_block, bool ignore_duplicate = false ); + + //void remove( const block_id_type& id ); + + //const block_state_ptr& root()const; + //const block_state_ptr& head()const; + //block_state_ptr pending_head()const; + + /** + * Returns the sequence of block states resulting from trimming the branch from the + * root block (exclusive) to the block with an id of `h` (inclusive) by removing any + * block states corresponding to block numbers greater than `trim_after_block_num`. + * + * The order of the sequence is in descending block number order. + * A block with an id of `h` must exist in the fork database otherwise this method will throw an exception. + */ + //branch_type fetch_branch( const block_id_type& h, uint32_t trim_after_block_num = std::numeric_limits::max() )const; + + + /** + * Returns the block state with a block number of `block_num` that is on the branch that + * contains a block with an id of`h`, or the empty shared pointer if no such block can be found. + */ + //block_state_ptr search_on_branch( const block_id_type& h, uint32_t block_num )const; + + /** + * Given two head blocks, return two branches of the fork graph that + * end with a common ancestor (same prior block) + */ + //pair< branch_type, branch_type > fetch_branch_from( const block_id_type& first, const block_id_type& second )const; + + + //void mark_valid( const block_state_ptr& h ); + + //static const uint32_t magic_number; + + //static const uint32_t min_supported_version; + //static const uint32_t max_supported_version; + + private: + //unique_ptr my; + }; + +} } /// eosio::chain diff --git a/libraries/chain/qc_database.cpp b/libraries/chain/qc_database.cpp new file mode 100644 index 0000000000..37fbd4918e --- /dev/null +++ b/libraries/chain/qc_database.cpp @@ -0,0 +1,492 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace eosio { namespace chain { + using boost::multi_index_container; + using namespace boost::multi_index; + + //const uint32_t fork_database::magic_number = 0x30510FDB; + + //const uint32_t fork_database::min_supported_version = 1; + //const uint32_t fork_database::max_supported_version = 1; + + // work around block_state::is_valid being private + //inline bool block_state_is_valid( const block_state& bs ) { + // return bs.is_valid(); + //} + + /** + * History: + * Version 1: initial version of the new refactored fork database portable format + */ + + //struct by_block_id; + //struct by_lib_block_num; + //struct by_prev; + /*typedef multi_index_container< + block_state_ptr, + indexed_by< + hashed_unique< tag, member, std::hash>, + ordered_non_unique< tag, const_mem_fun >, + ordered_unique< tag, + composite_key< block_state, + global_fun, + member, + member, + member + >, + composite_key_compare< + std::greater, + std::greater, + std::greater, + sha256_less + > + > + > + > fork_multi_index_type;*/ + +/* bool first_preferred( const block_header_state& lhs, const block_header_state& rhs ) { + return std::tie( lhs.dpos_irreversible_blocknum, lhs.block_num ) + > std::tie( rhs.dpos_irreversible_blocknum, rhs.block_num ); + } +*/ + struct qc_database_impl { + qc_database_impl( qc_database& self, const fc::path& data_dir ) + :self(self) + ,datadir(data_dir) + {} + + qc_database& self; + //fork_multi_index_type index; + //block_state_ptr root; // Only uses the block_header_state portion + //block_state_ptr head; + fc::path datadir; + + /*void add( const block_state_ptr& n, + bool ignore_duplicate, bool validate, + const std::function&, + const vector& )>& validator );*/ + }; + + + fork_database::qc_database( const fc::path& data_dir ) + :my( new qc_database_impl( *this, data_dir ) ) + {} + + + void qc_database::open( const std::function&, + const vector& )>& validator ) + { + if (!fc::is_directory(my->datadir)) + fc::create_directories(my->datadir); + + auto qc_db_dat = my->datadir / config::qcdb_filename; + if( fc::exists( qc_db_dat ) ) { + try { + //string content; + //fc::read_file_contents( qc_db_dat, content ); + + //fc::datastream ds( content.data(), content.size() ); + + // validate totem + //uint32_t totem = 0; + //fc::raw::unpack( ds, totem ); + /*EOS_ASSERT( totem == magic_number, fork_database_exception, + "Fork database file '${filename}' has unexpected magic number: ${actual_totem}. Expected ${expected_totem}", + ("filename", fork_db_dat.generic_string()) + ("actual_totem", totem) + ("expected_totem", magic_number) + );*/ + + // validate version + //uint32_t version = 0; + //fc::raw::unpack( ds, version ); + /*EOS_ASSERT( version >= min_supported_version && version <= max_supported_version, + fork_database_exception, + "Unsupported version of fork database file '${filename}'. " + "Fork database version is ${version} while code supports version(s) [${min},${max}]", + ("filename", fork_db_dat.generic_string()) + ("version", version) + ("min", min_supported_version) + ("max", max_supported_version) + );*/ + + /*block_header_state bhs; + fc::raw::unpack( ds, bhs ); + reset( bhs ); + + unsigned_int size; fc::raw::unpack( ds, size ); + for( uint32_t i = 0, n = size.value; i < n; ++i ) { + block_state s; + fc::raw::unpack( ds, s ); + // do not populate transaction_metadatas, they will be created as needed in apply_block with appropriate key recovery + s.header_exts = s.block->validate_and_extract_header_extensions(); + my->add( std::make_shared( move( s ) ), false, true, validator ); + } + block_id_type head_id; + fc::raw::unpack( ds, head_id ); + + if( my->root->id == head_id ) { + my->head = my->root; + } else { + my->head = get_block( head_id ); + EOS_ASSERT( my->head, fork_database_exception, + "could not find head while reconstructing fork database from file; '${filename}' is likely corrupted", + ("filename", fork_db_dat.generic_string()) ); + } + + auto candidate = my->index.get().begin(); + if( candidate == my->index.get().end() || !(*candidate)->is_valid() ) { + EOS_ASSERT( my->head->id == my->root->id, fork_database_exception, + "head not set to root despite no better option available; '${filename}' is likely corrupted", + ("filename", fork_db_dat.generic_string()) ); + } else { + EOS_ASSERT( !first_preferred( **candidate, *my->head ), fork_database_exception, + "head not set to best available option available; '${filename}' is likely corrupted", + ("filename", fork_db_dat.generic_string()) ); + }*/ + } FC_CAPTURE_AND_RETHROW( (qc_db_dat) ) + + fc::remove( qc_db_dat ); + } + } + + void qc_database::close() { + auto qc_db_dat = my->datadir / config::qcdb_filename; + +/* if( !my->root ) { + if( my->index.size() > 0 ) { + elog( "fork_database is in a bad state when closing; not writing out '${filename}'", + ("filename", fork_db_dat.generic_string()) ); + } + return; + }*/ + + /*std::ofstream out( fork_db_dat.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc ); + fc::raw::pack( out, magic_number ); + fc::raw::pack( out, max_supported_version ); // write out current version which is always max_supported_version + fc::raw::pack( out, *static_cast(&*my->root) ); + uint32_t num_blocks_in_fork_db = my->index.size(); + fc::raw::pack( out, unsigned_int{num_blocks_in_fork_db} ); + + const auto& indx = my->index.get(); + + auto unvalidated_itr = indx.rbegin(); + auto unvalidated_end = boost::make_reverse_iterator( indx.lower_bound( false ) ); + + auto validated_itr = unvalidated_end; + auto validated_end = indx.rend(); + + for( bool unvalidated_remaining = (unvalidated_itr != unvalidated_end), + validated_remaining = (validated_itr != validated_end); + + unvalidated_remaining || validated_remaining; + + unvalidated_remaining = (unvalidated_itr != unvalidated_end), + validated_remaining = (validated_itr != validated_end) + ) + { + auto itr = (validated_remaining ? validated_itr : unvalidated_itr); + + if( unvalidated_remaining && validated_remaining ) { + if( first_preferred( **validated_itr, **unvalidated_itr ) ) { + itr = unvalidated_itr; + ++unvalidated_itr; + } else { + ++validated_itr; + } + } else if( unvalidated_remaining ) { + ++unvalidated_itr; + } else { + ++validated_itr; + } + + fc::raw::pack( out, *(*itr) ); + } + + if( my->head ) { + fc::raw::pack( out, my->head->id ); + } else { + elog( "head not set in fork database; '${filename}' will be corrupted", + ("filename", fork_db_dat.generic_string()) ); + } + + my->index.clear();*/ + } + + qc_database::~qc_database() { + close(); + } + + /*void fork_database::reset( const block_header_state& root_bhs ) { + my->index.clear(); + my->root = std::make_shared(); + static_cast(*my->root) = root_bhs; + my->root->validated = true; + my->head = my->root; + } + + void fork_database::rollback_head_to_root() { + auto& by_id_idx = my->index.get(); + auto itr = by_id_idx.begin(); + while (itr != by_id_idx.end()) { + by_id_idx.modify( itr, [&]( block_state_ptr& bsp ) { + bsp->validated = false; + } ); + ++itr; + } + my->head = my->root; + }*/ + + /*void fork_database::advance_root( const block_id_type& id ) { + EOS_ASSERT( my->root, fork_database_exception, "root not yet set" ); + + auto new_root = get_block( id ); + EOS_ASSERT( new_root, fork_database_exception, + "cannot advance root to a block that does not exist in the fork database" ); + EOS_ASSERT( new_root->is_valid(), fork_database_exception, + "cannot advance root to a block that has not yet been validated" ); + + + deque blocks_to_remove; + for( auto b = new_root; b; ) { + blocks_to_remove.emplace_back( b->header.previous ); + b = get_block( blocks_to_remove.back() ); + EOS_ASSERT( b || blocks_to_remove.back() == my->root->id, fork_database_exception, "invariant violation: orphaned branch was present in forked database" ); + } + + // The new root block should be erased from the fork database index individually rather than with the remove method, + // because we do not want the blocks branching off of it to be removed from the fork database. + my->index.erase( my->index.find( id ) ); + + // The other blocks to be removed are removed using the remove method so that orphaned branches do not remain in the fork database. + for( const auto& block_id : blocks_to_remove ) { + remove( block_id ); + } + + // Even though fork database no longer needs block or trxs when a block state becomes a root of the tree, + // avoid mutating the block state at all, for example clearing the block shared pointer, because other + // parts of the code which run asynchronously may later expect it remain unmodified. + + my->root = new_root; + }*/ + + /*block_header_state_ptr fork_database::get_block_header( const block_id_type& id )const { + if( my->root->id == id ) { + return my->root; + } + + auto itr = my->index.find( id ); + if( itr != my->index.end() ) + return *itr; + + return block_header_state_ptr(); + }*/ + + /*void fork_database_impl::add( const block_state_ptr& n, + bool ignore_duplicate, bool validate, + const std::function&, + const vector& )>& validator ) + { + EOS_ASSERT( root, fork_database_exception, "root not yet set" ); + EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" ); + + auto prev_bh = self.get_block_header( n->header.previous ); + + EOS_ASSERT( prev_bh, unlinkable_block_exception, + "unlinkable block", ("id", n->id)("previous", n->header.previous) ); + + if( validate ) { + try { + const auto& exts = n->header_exts; + + if( exts.count(protocol_feature_activation::extension_id()) > 0 ) { + const auto& new_protocol_features = std::get(exts.lower_bound(protocol_feature_activation::extension_id())->second).protocol_features; + validator( n->header.timestamp, prev_bh->activated_protocol_features->protocol_features, new_protocol_features ); + } + } EOS_RETHROW_EXCEPTIONS( fork_database_exception, "serialized fork database is incompatible with configured protocol features" ) + } + + auto inserted = index.insert(n); + if( !inserted.second ) { + if( ignore_duplicate ) return; + EOS_THROW( fork_database_exception, "duplicate block added", ("id", n->id) ); + } + + auto candidate = index.get().begin(); + if( (*candidate)->is_valid() ) { + head = *candidate; + } + }*/ + + /*void fork_database::add( const block_state_ptr& n, bool ignore_duplicate ) { + my->add( n, ignore_duplicate, false, + []( block_timestamp_type timestamp, + const flat_set& cur_features, + const vector& new_features ) + {} + ); + }*/ + + /*const block_state_ptr& fork_database::root()const { return my->root; } + + const block_state_ptr& fork_database::head()const { return my->head; } + + block_state_ptr fork_database::pending_head()const { + const auto& indx = my->index.get(); + + auto itr = indx.lower_bound( false ); + if( itr != indx.end() && !(*itr)->is_valid() ) { + if( first_preferred( **itr, *my->head ) ) + return *itr; + } + + return my->head; + } + + branch_type fork_database::fetch_branch( const block_id_type& h, uint32_t trim_after_block_num )const { + branch_type result; + for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) { + if( s->block_num <= trim_after_block_num ) + result.push_back( s ); + } + + return result; + } + + block_state_ptr fork_database::search_on_branch( const block_id_type& h, uint32_t block_num )const { + for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) { + if( s->block_num == block_num ) + return s; + } + + return {}; + }*/ + + /** + * Given two head blocks, return two branches of the fork graph that + * end with a common ancestor (same prior block) + */ + /*pair< branch_type, branch_type > fork_database::fetch_branch_from( const block_id_type& first, + const block_id_type& second )const { + pair result; + auto first_branch = (first == my->root->id) ? my->root : get_block(first); + auto second_branch = (second == my->root->id) ? my->root : get_block(second); + + EOS_ASSERT(first_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", first)); + EOS_ASSERT(second_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", second)); + + while( first_branch->block_num > second_branch->block_num ) + { + result.first.push_back(first_branch); + const auto& prev = first_branch->header.previous; + first_branch = (prev == my->root->id) ? my->root : get_block( prev ); + EOS_ASSERT( first_branch, fork_db_block_not_found, + "block ${id} does not exist", + ("id", prev) + ); + } + + while( second_branch->block_num > first_branch->block_num ) + { + result.second.push_back( second_branch ); + const auto& prev = second_branch->header.previous; + second_branch = (prev == my->root->id) ? my->root : get_block( prev ); + EOS_ASSERT( second_branch, fork_db_block_not_found, + "block ${id} does not exist", + ("id", prev) + ); + } + + if (first_branch->id == second_branch->id) return result; + + while( first_branch->header.previous != second_branch->header.previous ) + { + result.first.push_back(first_branch); + result.second.push_back(second_branch); + const auto &first_prev = first_branch->header.previous; + first_branch = get_block( first_prev ); + const auto &second_prev = second_branch->header.previous; + second_branch = get_block( second_prev ); + EOS_ASSERT( first_branch, fork_db_block_not_found, + "block ${id} does not exist", + ("id", first_prev) + ); + EOS_ASSERT( second_branch, fork_db_block_not_found, + "block ${id} does not exist", + ("id", second_prev) + ); + } + + if( first_branch && second_branch ) + { + result.first.push_back(first_branch); + result.second.push_back(second_branch); + } + return result; + } /// fetch_branch_from + + /// remove all of the invalid forks built off of this id including this id + void fork_database::remove( const block_id_type& id ) { + deque remove_queue{id}; + const auto& previdx = my->index.get(); + const auto& head_id = my->head->id; + + for( uint32_t i = 0; i < remove_queue.size(); ++i ) { + EOS_ASSERT( remove_queue[i] != head_id, fork_database_exception, + "removing the block and its descendants would remove the current head block" ); + + auto previtr = previdx.lower_bound( remove_queue[i] ); + while( previtr != previdx.end() && (*previtr)->header.previous == remove_queue[i] ) { + remove_queue.emplace_back( (*previtr)->id ); + ++previtr; + } + } + + for( const auto& block_id : remove_queue ) { + auto itr = my->index.find( block_id ); + if( itr != my->index.end() ) + my->index.erase(itr); + } + } + + void fork_database::mark_valid( const block_state_ptr& h ) { + if( h->validated ) return; + + auto& by_id_idx = my->index.get(); + + auto itr = by_id_idx.find( h->id ); + EOS_ASSERT( itr != by_id_idx.end(), fork_database_exception, + "block state not in fork database; cannot mark as valid", + ("id", h->id) ); + + by_id_idx.modify( itr, []( block_state_ptr& bsp ) { + bsp->validated = true; + } ); + + auto candidate = my->index.get().begin(); + if( first_preferred( **candidate, *my->head ) ) { + my->head = *candidate; + } + } + + block_state_ptr fork_database::get_block(const block_id_type& id)const { + auto itr = my->index.find( id ); + if( itr != my->index.end() ) + return *itr; + return block_state_ptr(); + }*/ + +} } /// eosio::chain diff --git a/libraries/libfc/src/crypto/bls_utils.cpp.old b/libraries/libfc/src/crypto/bls_utils.cpp.old new file mode 100644 index 0000000000..30aab8e3dd --- /dev/null +++ b/libraries/libfc/src/crypto/bls_utils.cpp.old @@ -0,0 +1,12 @@ +#pragma once +#include + +namespace fc { namespace crypto { namespace blslib { + + static bool verify( const blslib::bls_public_key &pubkey, + const vector &message, + const bls_signature &signature){ + + } + +} } } // fc::crypto::blslib diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp new file mode 100644 index 0000000000..8fc6b9ee58 --- /dev/null +++ b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp @@ -0,0 +1,145 @@ +#pragma once +#include +#include +#include + +namespace eosio { namespace chain { + + const uint32_t INTERUPT_TIMEOUT = 6; //sufficient timeout for new leader to be selected + + class qc_chain { + public: + +/* const string msg_type_to_string(consensus_msg_type t) { + switch (t) { + case cm_new_view: return "cm_new_view"; + case cm_prepare: return "cm_prepare"; + case cm_pre_commit: return "cm_pre_commit"; + case cm_commit: return "cm_commit"; + case cm_decide: return "cm_decide"; + default: return "unknown"; + } + } + + enum qc_chain_state { + initializing = 1, + leading_view = 2, //only leader can lead view + processing_view = 3, + finished_view = 4 + };*/ + + qc_chain( ){}; + ~qc_chain(){}; +/* + digest_type get_digest_to_sign(consensus_msg_type msg_type, uint32_t view_number, digest_type digest_to_sign); + + void init(chain_plugin* chain_plug, std::set my_producers); //begins or resume a new qc chain + + void create_new_view(block_state hbs); //begins a new view + void request_new_view(); //request a new view from the leader +*/ + + name get_proposer(); + name get_leader(); + name get_incoming_leader(); + + bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, bool dual_set_mode); + + std::vector get_finalizers(); + + hs_proposal_message new_proposal_candidate(block_state& hbs); + hs_new_block_message new_new_block_candidate(block_state& hbs); + + void init(chain_plugin& chain_plug, std::set my_producers); + + block_header_state_ptr get_block_header( const block_id_type& id ); + + bool am_i_proposer(); + bool am_i_leader(); + bool am_i_incoming_leader(); + bool am_i_finalizer(); + + void process_proposal(hs_proposal_message msg); + void process_vote(hs_vote_message msg); + void process_new_view(hs_new_view_message msg); + void process_new_block(hs_new_block_message msg); + + void broadcast_hs_proposal(hs_proposal_message msg); + void broadcast_hs_vote(hs_vote_message msg); + void broadcast_hs_new_view(hs_new_view_message msg); + void broadcast_hs_new_block(hs_new_block_message msg); + + bool extends(block_id_type descendant, block_id_type ancestor); + + void on_beat(block_state& hbs); + + void update_high_qc(eosio::chain::quorum_certificate high_qc); + + void on_leader_rotate(block_id_type block_id); + + bool is_node_safe(hs_proposal_message proposal); + + //eosio::chain::quorum_certificate get_updated_quorum(hs_vote_message vote); + + //eosio::chain::quorum_certificate create_or_get_qc(hs_vote_message proposal); + + //void add_to_qc(eosio::chain::quorum_certificate& qc, name finalizer, fc::crypto::blslib::bls_signature sig); + + void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler + void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler + void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler + + void update(hs_proposal_message proposal); + void commit(block_header_state_ptr block); + + std::mutex _proposal_mutex; + std::mutex _vote_mutex; + std::mutex _new_view_mutex; + std::mutex _new_block_mutex; + + + +/* + + void process_confirmation_msg(confirmation_message msg, bool self_confirming); //process confirmation msg + void process_consensus_msg(consensus_message msg, bool self_leading); //process consensus msg + + void emit_confirm(confirmation_message msg); //send confirmation message + void emit_new_phase(consensus_message msg); //send consensus message + + void on_new_view_interrupt(); // + + void commit(block_header header); + + void print_state(); + + std::mutex _confirmation_mutex; + std::mutex _consensus_mutex; + + chain_plugin* _chain_plug = nullptr; + + std::set _my_producers; + + qc_chain_state _qc_chain_state; + + uint32_t _view_number; + chain::account_name _view_leader; + vector _view_finalizers; + + std::optional _prepareQC; + std::optional _lockedQC; + + fc::crypto::blslib::bls_private_key _private_key; + + quorum_certificate _currentQC; + + + uint32_t _view_liveness_threshold; + + vector _processed_confirmation_msgs; + vector _processed_consensus_msgs; +*/ + + }; +}} /// eosio::qc_chain \ No newline at end of file diff --git a/plugins/producer_plugin/qc_chain.cpp b/plugins/producer_plugin/qc_chain.cpp new file mode 100644 index 0000000000..55bff07ee1 --- /dev/null +++ b/plugins/producer_plugin/qc_chain.cpp @@ -0,0 +1,1355 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace eosio { namespace chain { + using boost::multi_index_container; + using namespace boost::multi_index; + + //todo : remove. bls12-381 key used for testing purposes + std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; + + fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); + + enum msg_type { + new_view = 1, + new_block = 2, + qc = 3, + vote = 4 + }; + + uint32_t _v_height; + + + const block_id_type NULL_BLOCK_ID = block_id_type("00"); + + const block_header_state_ptr NULL_BLOCK_HEADER_STATE_PTR = block_header_state_ptr(); + const block_state_ptr NULL_BLOCK_STATE_PTR = block_state_ptr(); + + block_id_type _b_leaf = NULL_BLOCK_ID; + block_id_type _b_lock = NULL_BLOCK_ID; + block_id_type _b_exec = NULL_BLOCK_ID; + + eosio::chain::quorum_certificate _high_qc; + + uint32_t _dual_set_height = 0; //0 if single-set mode + + eosio::chain::extended_schedule _schedule; + + chain_plugin* _chain_plug = nullptr; + std::set _my_producers; + + struct by_block_id{}; + struct by_block_num{}; + + typedef multi_index_container< + eosio::chain::quorum_certificate, + indexed_by< + hashed_unique< + tag, + BOOST_MULTI_INDEX_MEMBER(eosio::chain::quorum_certificate,block_id_type,block_id) + >, + ordered_non_unique< + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(eosio::chain::quorum_certificate,uint32_t,block_num) + > + > + > qc_store_type; + + typedef multi_index_container< + hs_proposal_message, + indexed_by< + hashed_unique< + tag, + BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,block_id_type,block_id) + >, + ordered_non_unique< + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint32_t,block_num) + > + > + > proposal_store_type; + + qc_store_type _qc_store; + proposal_store_type _proposal_store; + + digest_type get_digest_to_sign(fc::crypto::blslib::bls_signature agg_sig, block_id_type block_id){ + + digest_type h = digest_type::hash( std::make_pair( agg_sig, block_id ) ); + + return h; + + } + + name qc_chain::get_proposer(){ + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + return hbs->header.producer; + + } + + name qc_chain::get_leader(){ + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + return hbs->header.producer; + + } + + name qc_chain::get_incoming_leader(){ + + chain::controller& chain = _chain_plug->chain(); + + //verify if leader changed + signed_block_header current_block_header = chain.head_block_state()->header; + + block_timestamp_type next_block_time = current_block_header.timestamp.next(); + + producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); + + return p_auth.producer_name ; + + } + + std::vector qc_chain::get_finalizers(){ + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + return hbs->active_schedule.producers; + + } + + hs_proposal_message qc_chain::new_proposal_candidate(block_state& hbs) { + + hs_proposal_message b; + + b.block_id = hbs.header.calculate_id(); + b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + + return b; + } + + hs_new_block_message qc_chain::new_new_block_candidate(block_state& hbs) { + + hs_new_block_message b; + + b.block_id = hbs.header.calculate_id(); + b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + + return b; + } + + bool _quorum_met(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig){ + + //ilog("evaluating if _quorum_met"); + + if (finalizers.size() != _threshold){ + + //ilog("finalizers.size() ${size}", ("size",finalizers.size())); + return false; + + } + + //ilog("correct threshold"); + + /* fc::crypto::blslib::bls_public_key agg_key; + + for (name f : finalizers) { + + auto itr = es.bls_pub_keys.find(f); + + if (itr==es.bls_pub_keys.end()) return false; + + agg_key = fc::crypto::blslib::aggregate({agg_key, itr->second }); + + } + + std::vector msg = std::vector(block_id.data(), block_id.data() + 32); + + bool ok = fc::crypto::blslib::verify(agg_key, msg, agg_sig); + + return ok; */ + + return true; //temporary + + } + + bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, bool dual_set_mode){ + + if ( dual_set_mode && + qc.incoming_finalizers.has_value() && + qc.incoming_agg_sig.has_value()){ + return _quorum_met(schedule, qc.active_finalizers, qc.active_agg_sig) && _quorum_met(schedule, qc.incoming_finalizers.value(), qc.incoming_agg_sig.value()); + } + else { + return _quorum_met(schedule, qc.active_finalizers, qc.active_agg_sig); + } + + } + + void qc_chain::init(chain_plugin& chain_plug, std::set my_producers){ + + _chain_plug = &chain_plug; + _my_producers = my_producers; + + ilog("qc chain initialized -> my producers : "); + + auto itr = _my_producers.begin(); + while ( itr != _my_producers.end()){ + + ilog("${producer}", ("producer", *itr)); + + itr++; + } + + } + + block_header_state_ptr qc_chain::get_block_header( const block_id_type& id ){ + + //ilog("get_block_header "); + + chain::controller& chain = _chain_plug->chain(); + + return chain.fork_db().get_block_header(id); + + } + + bool qc_chain::am_i_proposer(){ + + name proposer = get_proposer(); + + //ilog("Proposer : ${proposer}", ("proposer", proposer)); + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); + + if (prod_itr==_my_producers.end()) return false; + else return true; + + } + + bool qc_chain::am_i_incoming_leader(){ + + name leader = get_incoming_leader(); + + //ilog("Incoming leader : ${leader}", ("leader", leader)); + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); + + if (prod_itr==_my_producers.end()) return false; + else return true; + + } + + bool qc_chain::am_i_leader(){ + + name leader = get_leader(); + + //ilog("Leader : ${leader}", ("leader", leader)); + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); + + if (prod_itr==_my_producers.end()) return false; + else return true; + + } + + bool qc_chain::am_i_finalizer(){ + + //ilog("am_i_finalizer"); + + std::vector finalizers = get_finalizers(); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); + + if (prod_itr!=finalizers.end()) return true; + + mf_itr++; + + } + + return false; + + } + + void qc_chain::process_proposal(hs_proposal_message msg){ + + //todo : block candidate validation hook (check if block is valid, etc.), return if not + + /* + + First, we verify if we have already are aware of the proposal, and if the QC was updated + + */ + + ilog("=== Process proposal #${block_num} ${block_id}", ("block_id", msg.block_id)("block_num", msg.block_num())); + + auto itr = _proposal_store.get().find( msg.block_id ); + + if (itr != _proposal_store.get().end()){ + + ilog("duplicate proposal"); + + return; //duplicate + + //if (itr->justify.has_value() && msg.justify.has_value() && itr->justify.value().active_agg_sig == msg.justify.value().active_agg_sig) return; + + } + else { + + ilog("new proposal. Adding to storage"); + + _proposal_store.insert(msg); //new block proposal + + } + + //check if I'm finalizer + + //ilog("updating state"); + + //update internal state + update(msg); + + //ilog("checking if I should sign proposal"); + + bool am_finalizer = am_i_finalizer(); + bool node_safe = is_node_safe(msg); + + //ilog("am_finalizer : ${am_finalizer}", ("am_finalizer", am_finalizer)); + //ilog("node_safe : ${node_safe}", ("node_safe", node_safe)); + + bool signature_required = am_finalizer && node_safe; + + + //if I am a finalizer for this proposal, test safenode predicate for possible vote + if (signature_required){ + + //ilog("signature required"); + + _v_height = msg.block_num(); + + /* + Sign message. + + In Hotstuff, we need to sign a tuple of (msg.view_type, msg.view_number and msg.node). + + In our implementation, the view_type is generic, and the view_number and message node are both contained in the block_id. + + Therefore, we can ensure uniqueness by replacing the view_type with msg.block_candidate.justify.agg_sig. + + The digest to sign now becomes the tuple (msg.block_candidate.justify.agg_sig, msg.block_candidate.block_id). + + */ + + fc::crypto::blslib::bls_signature agg_sig; + + if (msg.justify.has_value()) agg_sig = msg.justify.value().active_agg_sig; + + digest_type digest = get_digest_to_sign(agg_sig, msg.block_id); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + //iterate over all my finalizers and sign / broadcast for each that is in the schedule + std::vector finalizers = get_finalizers(); + + ilog("signed proposal. Broadcasting for each of my producers"); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); + + if (prod_itr!=finalizers.end()) { + + fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer + + hs_vote_message v_msg = {msg.block_id, prod_itr->producer_name, sig}; + + broadcast_hs_vote(v_msg); + + }; + + mf_itr++; + + } + + //check for leader change + on_leader_rotate(msg.block_id); + + } + + + } + + void qc_chain::process_vote(hs_vote_message msg){ + + //check for duplicate or invalid vote, return in either case + //abstracted [...] + + bool am_leader = am_i_leader(); //am I leader? + + if(!am_leader) return; + + ilog("=== Process vote from ${finalizer}", ("finalizer", msg.finalizer)); + + eosio::chain::quorum_certificate qc; + + //only leader need to take action on votes + + qc_store_type::nth_index<0>::type::iterator itr = _qc_store.get().find( msg.block_id ); + + if (itr!=_qc_store.get().end()){ + + bool quorum_met = is_quorum_met(*itr, _schedule, false); + + if (!quorum_met){ + + _qc_store.modify( itr, [&]( auto& qc ) { + qc.active_finalizers.push_back(msg.finalizer); + qc.active_agg_sig = fc::crypto::blslib::aggregate({qc.active_agg_sig, msg.sig }); + }); + + quorum_met = is_quorum_met(*itr, _schedule, false); + + if (quorum_met){ + + ilog("=== Quorum met on #${block_num} : ${block_id}", ("block_num", compute_block_num(msg.block_id))("block_id", msg.block_id)); + + update_high_qc(*itr); + + chain::controller& chain = _chain_plug->chain(); + + //todo : optimistically-responsive liveness progress + + } + + } + + } + else { + + ilog(" must create new qc for proposal"); + + //new QC is created + + qc.block_id = msg.block_id; + qc.active_finalizers.push_back(msg.finalizer); + qc.active_agg_sig = msg.sig; + + _qc_store.insert(qc); + + } + + } + + void qc_chain::process_new_view(hs_new_view_message msg){ + + ilog("=== Process new view ==="); + + bool am_leader = am_i_leader(); //am I leader? + + if(!am_leader) return; + + } + + void qc_chain::process_new_block(hs_new_block_message msg){ + + //ilog("=== Process new block ==="); + + } + + void qc_chain::broadcast_hs_proposal(hs_proposal_message msg){ + + //ilog("=== broadcast_hs_proposal ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_proposal_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_proposal_msg(ptr); + + process_proposal(msg); + + } + + + void qc_chain::broadcast_hs_vote(hs_vote_message msg){ + + //ilog("=== broadcast_hs_vote ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_vote_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_vote_msg(ptr); + + process_vote(msg); + + } + + void qc_chain::broadcast_hs_new_view(hs_new_view_message msg){ + + //ilog("=== broadcast_hs_new_view ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_new_view_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_new_view_msg(ptr); + + //process_new_view(msg); //notify ourselves + + } + + void qc_chain::broadcast_hs_new_block(hs_new_block_message msg){ + + //ilog("=== broadcast_hs_new_block ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_new_block_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_new_block_msg(ptr); + + //process_new_block(msg); //notify ourselves + + } + + //extends predicate + bool qc_chain::extends(block_id_type descendant, block_id_type ancestor){ + + //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified + + block_header_state_ptr itr = get_block_header(descendant); + //block_header_state_ptr a_itr = get_block_header(ancestor); + +/* if (a_itr == NULL_BLOCK_HEADER_STATE_PTR){ + ilog("ancestor does't exist, returning true"); + return true; + }*/ + + while (itr!=NULL_BLOCK_HEADER_STATE_PTR){ + + itr = get_block_header(itr->header.previous); + + if (itr->id == ancestor) return true; + + + } + + ilog(" ***** extends returned false : could not find #${d_block_num} ${d_block_id} descending from #${a_block_num} ${a_block_id} ", + ("d_block_num", compute_block_num(descendant)) + ("d_block_id", descendant) + ("a_block_num", compute_block_num(ancestor)) + ("a_block_id", ancestor)); + + return false; + + } + + void qc_chain::on_beat(block_state& hbs){ + + ilog("=== on beat ==="); + + if (hbs.header.producer == "eosio"_n) return ; + + bool am_proposer = am_i_proposer(); + bool am_leader = am_i_leader(); + + //ilog("=== am_proposer = ${am_proposer}", ("am_proposer", am_proposer)); + //ilog("=== am_leader = ${am_leader}", ("am_leader", am_leader)); + + if (!am_proposer && !am_leader){ + + return; //nothing to do + + } + + //if I am the leader + if (am_leader){ + + //if I'm not also the proposer, perform block validation as required + if (!am_proposer){ + + //todo : extra validation + + } + + hs_proposal_message block_candidate = new_proposal_candidate(hbs); + + _b_leaf = block_candidate.block_id; + + ilog("=== broadcasting proposal = #${block_num} ${block_id}", ("block_id", block_candidate.block_id)("block_num", block_candidate.block_num())); + + broadcast_hs_proposal(block_candidate); + + } + else { + + //if I'm only a proposer and not the leader, I send a new block message + + hs_new_block_message block_candidate = new_new_block_candidate(hbs); + + ilog("=== broadcasting new block = #${block_num} ${block_id}", ("block_id", block_candidate.block_id)("block_num", block_candidate.block_num())); + + broadcast_hs_new_block(block_candidate); + + } + + + } + + void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ + // if new high QC is higher than current, update to new + if (high_qc.block_num()>_high_qc.block_num()){ + + ilog("=== updating high qc, now is : #${block_num} ${block_id}", ("block_num", compute_block_num(high_qc.block_id))("block_id", high_qc.block_id)); + + _high_qc = high_qc; + _b_leaf = _high_qc.block_id; + + } + + } + + void qc_chain::on_leader_rotate(block_id_type block_id){ + + //ilog("on_leader_rotate"); + + chain::controller& chain = _chain_plug->chain(); + + //verify if leader changed + signed_block_header current_block_header = chain.head_block_state()->header; + + block_timestamp_type next_block_time = current_block_header.timestamp.next(); + + ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", + ("old_timestamp", current_block_header.timestamp)("new_timestamp", current_block_header.timestamp.next())); + + producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); + + if (current_block_header.producer != p_auth.producer_name){ + + ilog("=== rotating leader : ${old_leader} -> ${new_leader} ", + ("old_leader", current_block_header.producer)("new_leader", p_auth.producer_name)); + + //leader changed, we send our new_view message + + hs_new_view_message new_view; + + new_view.high_qc = _high_qc; + + broadcast_hs_new_view(new_view); + } + + + } + + //safenode predicate + bool qc_chain::is_node_safe(hs_proposal_message proposal){ + + //ilog("=== is_node_safe ==="); + + bool monotony_check = false; + bool safety_check = false; + bool liveness_check = false; + + if (proposal.block_num() > _v_height){ + monotony_check = true; + } + + if (_b_lock != NULL_BLOCK_ID){ + + //Safety check : check if this proposal extends the chain I'm locked on + if (extends(proposal.block_id, _b_lock)){ + safety_check = true; + } + + //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. + if (!proposal.justify.has_value()) liveness_check = true; + else if (proposal.justify.value().block_num() > compute_block_num(_b_lock)){ + liveness_check = true; + } + + } + else { + + //if we're not locked on anything, means the protocol just activated or chain just launched + liveness_check = true; + safety_check = true; + } + + ilog("=== safety check : monotony : ${monotony_check}, liveness : ${liveness_check}, safety : ${safety_check}", + ("monotony_check", monotony_check) + ("liveness_check", liveness_check) + ("safety_check", safety_check)); + + return monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully + + } + + //on proposal received, called from network thread + void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ + + //ilog("=== on_hs_proposal_msg ==="); + std::lock_guard g( this->_proposal_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_proposal(msg); + + } + + //on vote received, called from network thread + void qc_chain::on_hs_vote_msg(hs_vote_message msg){ + + //ilog("=== on_hs_vote_msg ==="); + std::lock_guard g( this->_vote_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_vote(msg); + + } + + //on new view received, called from network thread + void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ + + //ilog("=== on_hs_new_view_msg ==="); + std::lock_guard g( this->_new_view_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_new_view(msg); + + } + + //on new block received, called from network thread + void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ + + //ilog("=== on_hs_new_block_msg ==="); + std::lock_guard g( this->_new_block_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_new_block(msg); + + } + + void qc_chain::update(hs_proposal_message proposal){ + + + ilog("=== update internal state ==="); + + chain::controller& chain = _chain_plug->chain(); + + //proposal_store_type::nth_index<0>::type::iterator b_new_itr = _proposal_store.get().find( proposal.block_id ); //guaranteed to exist + + //should all be guaranteed to exist ? + proposal_store_type::nth_index<0>::type::iterator b_2_itr; + proposal_store_type::nth_index<0>::type::iterator b_1_itr; + proposal_store_type::nth_index<0>::type::iterator b_itr; + + b_2_itr = _proposal_store.get().find( proposal.justify.value().block_id ); + b_1_itr = _proposal_store.get().find( b_2_itr->justify.value().block_id ); + b_itr = _proposal_store.get().find( b_1_itr->justify.value().block_id ); + + block_header_state_ptr b_2_header = get_block_header(b_2_itr->block_id); + block_header_state_ptr b_1_header = get_block_header(b_1_itr->block_id); + block_header_state_ptr b_header = get_block_header(b_itr->block_id); + + ilog("b_2_itr->block_id : #${block_num}: ${block_id}" ,("block_num", compute_block_num(b_2_itr->block_id))("block_id", b_2_itr->block_id)); + ilog("b_1_itr->block_id : #${block_num}:${block_id}" ,("block_num", compute_block_num(b_1_itr->block_id))("block_id", b_1_itr->block_id)); + ilog("b_itr->block_id : #${block_num}:${block_id}" ,("block_num", compute_block_num(b_itr->block_id))("block_id", b_itr->block_id)); + + //todo : check if pending transition of finalizer set exists + + + if (b_2_itr==_proposal_store.get().end()) return; + //ilog("proposal.justify exists"); + + update_high_qc(proposal.justify.value()); + + if (b_1_itr==_proposal_store.get().end()) return; + //ilog("b_2_itr->justify exists"); + + if (compute_block_num(b_1_itr->block_id) > compute_block_num(_b_lock)){ + ilog("commit phase on block : #${block_num}:${block_id}" ,("block_num", compute_block_num(b_1_itr->block_id))("block_id", b_1_itr->block_id)); + _b_lock = b_1_itr->block_id; //commit phase on b1 + //ilog("lock confirmed"); + } + + if (b_itr==_proposal_store.get().end()) return; + //ilog("b_1_itr->justify exists"); + + ilog("parent relationship verification : b_2->previous ${b_2_previous} b_1->block_id ${b_1_block_id} b_1->previous ${b_1_previous} b->block_id ${b_block_id}", + ("b_2_previous", b_2_header->header.previous)("b_1_block_id", b_1_itr->block_id)("b_1_previous",b_1_header->header.previous)("b_block_id",b_itr->block_id)); + + //direct parent relationship verification + if (b_2_header->header.previous == b_1_itr->block_id && b_1_header->header.previous == b_itr->block_id){ + + ilog("direct parent relationship verified"); + + //if we are currently operating in dual set mode reaching this point, and the block we are about to commit has a height higher or equal to me._dual_set_height, it means we have reached extended quorum on a view ready to be committed, so we can transition into single_set mode again, where the incoming finalizer set becomes the active finalizer set + if (_dual_set_height != 0 && compute_block_num(b_itr->block_id) >= _dual_set_height){ + + ilog("transitionning out of dual set mode"); + + //sanity check to verify quorum on justification for b (b1), should always evaluate to true + //if (b_itr->justify.extended_quorum_met()){ + + //reset internal state to single_set mode, with new finalizer set + //me._schedule.block_finalizers = me_.schedule.incoming_finalizers; + //me_.schedule.incoming_finalizers = null; + //me._dual_set_height = -1; + + //} + + } + + commit(b_header); + + ilog("last executed block : #${block_num} ${block_id}", ("block_num", compute_block_num(b_itr->block_id))("block_id", b_itr->block_id)); + + _b_exec = b_itr->block_id; //decide phase on b + + ilog("completed commit"); + + } + else { + + ilog("could not verify direct parent relationship"); + + } + + + //ilog("=== end update ==="); + + } + + void qc_chain::commit(block_header_state_ptr block){ + + block_header_state_ptr b_exec = get_block_header(_b_exec); + + bool sequence_respected; + + if (b_exec == NULL_BLOCK_HEADER_STATE_PTR) { + ilog("first block committed"); + sequence_respected = true; + + } + else sequence_respected = b_exec->header.block_num() < block->header.block_num(); + + if (sequence_respected){ + + block_header_state_ptr p_itr = get_block_header(block->header.previous); + + if (p_itr != NULL_BLOCK_HEADER_STATE_PTR){ + + ilog("=== recursively committing" ); + + commit(p_itr); //recursively commit all non-committed ancestor blocks sequentially first + + } + + //execute block cmd + //abstracted [...] + + ilog("=== committed block #${block_id}", ("block_id", block->header.block_num())); + + } + + } + +/* + digest_type qc_chain::get_digest_to_sign(consensus_msg_type msg_type, uint32_t view_number, digest_type digest_to_sign){ + + string s_cmt = msg_type_to_string(msg_type); + string s_view_number = to_string(view_number); + + string s_c = s_cmt + s_view_number; + + digest_type h1 = digest_type::hash(s_c); + digest_type h2 = digest_type::hash( std::make_pair( h1, digest_to_sign ) ); + + return h2; + + } + + void qc_chain::init(chain_plugin* chain_plug, std::set my_producers){ + + std::vector seed_1 = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; + + ilog("init qc chain"); + + _qc_chain_state = initializing; + _my_producers = my_producers; + + _chain_plug = chain_plug; + + _private_key = fc::crypto::blslib::bls_private_key(seed_1); + + } + + //create a new view based on the block we just produced + void qc_chain::create_new_view(block_state hbs){ + + _view_number++; + _view_leader = hbs.header.producer; + _view_finalizers = hbs.active_schedule.producers; + + _qc_chain_state = leading_view; + + digest_type previous_bmroot = hbs.blockroot_merkle.get_root(); + digest_type schedule_hash = hbs.pending_schedule.schedule_hash; + + digest_type header_bmroot = digest_type::hash(std::make_pair(hbs.header.digest(), previous_bmroot)); + digest_type digest_to_sign = digest_type::hash(std::make_pair(header_bmroot, schedule_hash)); + + consensus_node cn = {hbs.header, previous_bmroot, schedule_hash, digest_to_sign}; + + std::optional qc; + + if (_prepareQC.has_value()) qc = _prepareQC.value(); + else qc = std::nullopt; + + consensus_message msg = {cm_prepare, _view_number, cn, qc} ; + + ilog("creating new view #${view_number} : leader : ${view_leader}", + ("view_number", _view_number)("view_leader", _view_leader)); + + vector finalizers; + + _currentQC = {msg.msg_type, msg.view_number, msg.node, finalizers, fc::crypto::blslib::bls_signature("")};; + + emit_new_phase(msg); + + + } + + void qc_chain::request_new_view(){ + + //ilog("request new view"); + + _view_number++; + + _qc_chain_state = processing_view; + + //consensus_node cn = _prepareQC.node; + //consensus_message msg = {cm_new_view, _view_number, cn, std::nullopt}; + + //emit_new_phase(msg); + + } + +*/ + +/* + + void qc_chain::process_confirmation_msg(confirmation_message msg, bool self_confirming){ + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == _view_leader; }); + + if (prod_itr==_my_producers.end()) return; //if we're not producing, we can ignore any confirmation messages + + auto itr = std::find_if(_processed_confirmation_msgs.begin(), _processed_confirmation_msgs.end(), [ &msg](confirmation_message m){ + return m.msg_type == msg.msg_type && + m.view_number == msg.view_number && + m.node.digest_to_sign == msg.node.digest_to_sign && + m.finalizer == msg.finalizer; + }); + + if (itr!=_processed_confirmation_msgs.end()) { + //ilog("WRONG already processed this message"); + return; //already processed + } + else{ + //ilog("new confirmation message. Processing..."); + _processed_confirmation_msgs.push_back(msg); + + if (_processed_confirmation_msgs.size()==100) _processed_confirmation_msgs.erase(_processed_confirmation_msgs.begin()); + + } + + if (_currentQC.msg_type == msg.msg_type && //check if confirmation message is for that QC + _currentQC.view_number == msg.view_number){ + + if (std::find(_currentQC.finalizers.begin(), _currentQC.finalizers.end(), msg.finalizer) == _currentQC.finalizers.end()){ + + //ilog("new finalizer vote received for this QC"); + + //verify signature + fc::crypto::blslib::bls_public_key pk = _private_key.get_public_key(); + + digest_type digest = get_digest_to_sign(msg.msg_type, msg.view_number, msg.node.digest_to_sign ); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + bool ok = verify(pk, h, msg.sig); + + if (ok==false){ + //ilog("WRONG signature invalid"); + return; + } + + fc::crypto::blslib::bls_signature n_sig; + + if (_currentQC.finalizers.size() == 0) n_sig = msg.sig; + else n_sig = fc::crypto::blslib::aggregate({_currentQC.sig,msg.sig}); + + + _currentQC.sig = n_sig; + _currentQC.finalizers.push_back(msg.finalizer); + + if (_currentQC.finalizers.size()==14){ + + ilog("reached quorum on ${msg_type}, can proceed with next phase", + ("msg_type", msg.msg_type)); + + //received enough confirmations to move to next phase + consensus_msg_type next_phase; + + switch (_currentQC.msg_type) { + case cm_prepare: + next_phase = cm_pre_commit; + _prepareQC = _currentQC; + break; + case cm_pre_commit: + next_phase = cm_commit; + break; + case cm_commit: + next_phase = cm_decide; + break; + } + + consensus_message n_msg = {next_phase, _currentQC.view_number, _currentQC.node, _currentQC}; + + vector finalizers; + + quorum_certificate qc = {next_phase, _currentQC.view_number, _currentQC.node, finalizers, fc::crypto::blslib::bls_signature("")}; + + _currentQC = qc; + + emit_new_phase(n_msg); + + //ilog("sent next phase message"); + + if (next_phase==cm_decide){ + + uint32_t block_height = n_msg.node.header.block_num(); + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + uint32_t distance_from_head = hbs->header.block_num() - block_height; + + ilog("decide decision has been reached on view #${view_number}. Block #${block_height} can be commited safely. Distance from head : ${distance_from_head}", + ("view_number", msg.view_number) + ("block_height", block_height) + ("distance_from_head", distance_from_head)); + + _qc_chain_state=finished_view; + + //if we're still producing, we can start a new view + if (std::find(_my_producers.begin(), _my_producers.end(), hbs->header.producer) != _my_producers.end()){ + create_new_view(*hbs); + } + + } + + } + else { + //uint32_t remaining = 14 - _currentQC.finalizers.size(); + + //ilog("need ${remaining} more votes to move to next phase", ("remaining", remaining)); + } + + } + else { + //ilog("WRONG already received vote for finalizer on this QC "); + + + } + + } + else { + //confirmation applies to another message + //ilog("WRONG QC"); + + } + + } + + void qc_chain::process_consensus_msg(consensus_message msg, bool self_leading){ + + + auto itr = std::find_if(_processed_consensus_msgs.begin(), _processed_consensus_msgs.end(), [ &msg](consensus_message m){ + return m.msg_type == msg.msg_type && + m.view_number == msg.view_number && + m.node.digest_to_sign == msg.node.digest_to_sign; + }); + + if (itr!=_processed_consensus_msgs.end()){ + //ilog("WRONG already processed this message"); + return; //already processed + } + else { + //ilog("new consensus message. Processing..."); + _processed_consensus_msgs.push_back(msg); + + if (_processed_consensus_msgs.size()==100) _processed_consensus_msgs.erase(_processed_consensus_msgs.begin()); + + } + + //TODO validate message + + digest_type digest = get_digest_to_sign(msg.msg_type, msg.view_number, msg.node.digest_to_sign ); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + //if we're leading the view, reject the consensus message + //if (_qc_chain_state==leading_view) return; + + if (msg.justify.has_value()) { + + auto justify = msg.justify.value(); + + if (justify.finalizers.size() == 14){ + + fc::crypto::blslib::bls_public_key agg_pk = _private_key.get_public_key(); + + //verify QC + for (size_t i = 1 ; i < justify.finalizers.size();i++){ + agg_pk = fc::crypto::blslib::aggregate({agg_pk,_private_key.get_public_key()}); + } + + digest_type digest_j = get_digest_to_sign(justify.msg_type, justify.view_number, justify.node.digest_to_sign ); + std::vector hj = std::vector(digest_j.data(), digest_j.data() + 32); + + bool ok = verify(agg_pk, hj, justify.sig); + + if (ok==false){ + //ilog("WRONG aggregate signature invalid"); + return; + } + + _view_number = msg.view_number; + + if (justify.msg_type == cm_pre_commit){ + _prepareQC = justify; + } + else if (justify.msg_type == cm_pre_commit){ + _lockedQC = justify; + } + } + else { + + //ilog("WRONG invalid consensus message justify argument"); + + return ; + } + } + + if (_qc_chain_state==initializing || _qc_chain_state==finished_view ) { + _view_number = msg.view_number; + _view_leader = msg.node.header.producer; + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + _view_finalizers = hbs->active_schedule.producers; + + _qc_chain_state=processing_view; + + } + + //if we received a commit decision and we are not also leading this round + if (msg.msg_type == cm_decide && self_leading == false){ + + uint32_t block_height = msg.node.header.block_num(); + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + uint32_t distance_from_head = hbs->header.block_num() - block_height; + + ilog("decide decision has been reached on view #${view_number}. Block #${block_height} can be commited safely. Distance from head : ${distance_from_head}", + ("view_number", msg.view_number) + ("block_height", block_height) + ("distance_from_head", distance_from_head)); + + //if current producer is not previous view leader, we must send a new_view message with our latest prepareQC + if (hbs->header.producer != _view_leader){ + //_view_number++; + _view_leader = hbs->header.producer; + _qc_chain_state=finished_view; + } + + return; + + } + else { + + auto p_itr = _my_producers.begin(); + + while(p_itr!= _my_producers.end()){ + + chain::account_name finalizer = *p_itr; + + auto itr = std::find_if(_view_finalizers.begin(), _view_finalizers.end(), [&](const auto& asp){ return asp.producer_name == finalizer; }); + + if (itr!= _view_finalizers.end()){ + + //ilog("Signing confirmation..."); + + fc::crypto::blslib::bls_signature sig = _private_key.sign(h);; + + confirmation_message n_msg = {msg.msg_type, msg.view_number, msg.node, finalizer, sig}; + + //ilog("Sending confirmation message for ${finalizer}", ("finalizer", finalizer)); + + emit_confirm(n_msg); + + } + else { + //finalizer not in view schedule + //ilog("WRONG consensus ${finalizer}", ("finalizer", finalizer)); + + } + + p_itr++; + } + + } + } + + void qc_chain::emit_confirm(confirmation_message msg){ + + chain::controller& chain = _chain_plug->chain(); + + confirmation_message_ptr ptr = std::make_shared(msg); + + chain.commit_confirmation_msg(ptr); + + process_confirmation_msg(msg, true); //notify ourselves, in case we are also the view leader + + } + + void qc_chain::emit_new_phase(consensus_message msg){ + + chain::controller& chain = _chain_plug->chain(); + + ilog("emit new phase ${msg_type}... view #${view_number} on block #${block_num}", + ("msg_type",msg.msg_type) + ("view_number",msg.view_number) + ("block_num",msg.node.header.block_num()) ); + + consensus_message_ptr ptr = std::make_shared(msg); + + chain.commit_consensus_msg(ptr); + + process_consensus_msg(msg, true); //notify ourselves, in case we are also running finalizers + + } + + void qc_chain::on_new_view_interrupt(){ + + } + + void qc_chain::commit(block_header header){ + + } + + void qc_chain::print_state(){ + + ilog("QC CHAIN STATE : "); + + ilog(" view number : ${view_number}, view leader : ${view_leader}", + ("view_number", _view_number) + ("view_leader", _view_leader)); + + + if (_prepareQC.has_value()){ + + quorum_certificate prepareQC = _prepareQC.value(); + + ilog(" prepareQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", + ("msg_type", prepareQC.msg_type) + ("view_number", prepareQC.view_number) + ("block_num", prepareQC.node.header.block_num())); + + ilog(" finalizers : "); + + for (int i = 0 ; i < prepareQC.finalizers.size(); i++){ + ilog(" ${finalizer}", + ("finalizer", prepareQC.finalizers[i])); + } + + } + else { + ilog(" no prepareQC"); + } + + + if (_lockedQC.has_value()){ + + quorum_certificate lockedQC = _lockedQC.value(); + + ilog(" lockedQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", + ("msg_type", lockedQC.msg_type) + ("view_number", lockedQC.view_number) + ("block_num", lockedQC.node.header.block_num())); + + ilog(" finalizers : "); + + for (int i = 0 ; i < lockedQC.finalizers.size(); i++){ + ilog(" ${finalizer}", + ("finalizer", lockedQC.finalizers[i])); + } + + } + else { + ilog(" no _lockedQC"); + } + + ilog(" _currentQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", + ("msg_type", _currentQC.msg_type) + ("view_number", _currentQC.view_number) + ("block_num", _currentQC.node.header.block_num())); + + ilog(" finalizers : "); + + for (int i = 0 ; i < _currentQC.finalizers.size(); i++){ + ilog(" ${finalizer}", + ("finalizer", _currentQC.finalizers[i])); + } + + ilog(" _processed_confirmation_msgs count : ${count}", + ("count", _processed_confirmation_msgs.size())); + + ilog(" _processed_consensus_msgs count : ${count}", + ("count", _processed_consensus_msgs.size())); + + + } +*/ +}} + + diff --git a/plugins/producer_plugin/qc_chain.old.cpp b/plugins/producer_plugin/qc_chain.old.cpp new file mode 100644 index 0000000000..76ef632e68 --- /dev/null +++ b/plugins/producer_plugin/qc_chain.old.cpp @@ -0,0 +1,573 @@ +#include + +namespace eosio { namespace chain { + + digest_type qc_chain::get_digest_to_sign(consensus_msg_type msg_type, uint32_t view_number, digest_type digest_to_sign){ + + string s_cmt = msg_type_to_string(msg_type); + string s_view_number = to_string(view_number); + + string s_c = s_cmt + s_view_number; + + digest_type h1 = digest_type::hash(s_c); + digest_type h2 = digest_type::hash( std::make_pair( h1, digest_to_sign ) ); + + return h2; + + } + + void qc_chain::init(chain_plugin* chain_plug, std::set my_producers){ + + std::vector seed_1 = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; + + ilog("init qc chain"); + + _qc_chain_state = initializing; + _my_producers = my_producers; + + _chain_plug = chain_plug; + + _private_key = fc::crypto::blslib::bls_private_key(seed_1); + + } + + //create a new view based on the block we just produced + void qc_chain::create_new_view(block_state hbs){ + + _view_number++; + _view_leader = hbs.header.producer; + _view_finalizers = hbs.active_schedule.producers; + + _qc_chain_state = leading_view; + + digest_type previous_bmroot = hbs.blockroot_merkle.get_root(); + digest_type schedule_hash = hbs.pending_schedule.schedule_hash; + + digest_type header_bmroot = digest_type::hash(std::make_pair(hbs.header.digest(), previous_bmroot)); + digest_type digest_to_sign = digest_type::hash(std::make_pair(header_bmroot, schedule_hash)); + + consensus_node cn = {hbs.header, previous_bmroot, schedule_hash, digest_to_sign}; + + std::optional qc; + + if (_prepareQC.has_value()) qc = _prepareQC.value(); + else qc = std::nullopt; + + consensus_message msg = {cm_prepare, _view_number, cn, qc} ; + + ilog("creating new view #${view_number} : leader : ${view_leader}", + ("view_number", _view_number)("view_leader", _view_leader)); + + vector finalizers; + + _currentQC = {msg.msg_type, msg.view_number, msg.node, finalizers, fc::crypto::blslib::bls_signature("")};; + + emit_new_phase(msg); + + + } + + void qc_chain::request_new_view(){ + + //ilog("request new view"); + + _view_number++; + + _qc_chain_state = processing_view; + + //consensus_node cn = _prepareQC.node; + //consensus_message msg = {cm_new_view, _view_number, cn, std::nullopt}; + + //emit_new_phase(msg); + + } + + //called from network thread + void qc_chain::on_confirmation_msg(confirmation_message msg){ + + std::lock_guard g( this->_confirmation_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_confirmation_msg(msg, false); + + } + + //called from network thread + void qc_chain::on_consensus_msg(consensus_message msg){ + + std::lock_guard g( this->_consensus_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_consensus_msg(msg, false); + + } + + void qc_chain::process_confirmation_msg(confirmation_message msg, bool self_confirming){ + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == _view_leader; }); + + if (prod_itr==_my_producers.end()) return; //if we're not producing, we can ignore any confirmation messages + +/* ilog("got notified of confirmation message: ${msg_type} for view ${view_number} ${self_confirming}", + ("msg_type", msg.msg_type) + ("view_number", msg.view_number) + ("self_confirming", self_confirming));*/ + + auto itr = std::find_if(_processed_confirmation_msgs.begin(), _processed_confirmation_msgs.end(), [ &msg](confirmation_message m){ + return m.msg_type == msg.msg_type && + m.view_number == msg.view_number && + m.node.digest_to_sign == msg.node.digest_to_sign && + m.finalizer == msg.finalizer; + }); + + if (itr!=_processed_confirmation_msgs.end()) { + //ilog("WRONG already processed this message"); + return; //already processed + } + else{ + //ilog("new confirmation message. Processing..."); + _processed_confirmation_msgs.push_back(msg); + + if (_processed_confirmation_msgs.size()==100) _processed_confirmation_msgs.erase(_processed_confirmation_msgs.begin()); + + } + + if (_currentQC.msg_type == msg.msg_type && //check if confirmation message is for that QC + _currentQC.view_number == msg.view_number){ + + if (std::find(_currentQC.finalizers.begin(), _currentQC.finalizers.end(), msg.finalizer) == _currentQC.finalizers.end()){ + + //ilog("new finalizer vote received for this QC"); + + //verify signature + fc::crypto::blslib::bls_public_key pk = _private_key.get_public_key(); + + digest_type digest = get_digest_to_sign(msg.msg_type, msg.view_number, msg.node.digest_to_sign ); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + bool ok = verify(pk, h, msg.sig); + +/* ilog("verification - key: ${pk} hash: ${h} sig: ${sig}", + ("agg_pk", pk.to_string()) + ("h", h) + ("sig", msg.sig.to_string()));*/ + + if (ok==false){ + //ilog("WRONG signature invalid"); + return; + } + + fc::crypto::blslib::bls_signature n_sig; + + if (_currentQC.finalizers.size() == 0) n_sig = msg.sig; + else n_sig = fc::crypto::blslib::aggregate({_currentQC.sig,msg.sig}); + +/* ilog("n_sig updated : ${n_sig}", + ("n_sig", n_sig.to_string()));*/ + + _currentQC.sig = n_sig; + _currentQC.finalizers.push_back(msg.finalizer); + + if (_currentQC.finalizers.size()==14){ + + ilog("reached quorum on ${msg_type}, can proceed with next phase", + ("msg_type", msg.msg_type)); + + //received enough confirmations to move to next phase + consensus_msg_type next_phase; + + switch (_currentQC.msg_type) { + case cm_prepare: + next_phase = cm_pre_commit; + _prepareQC = _currentQC; + break; + case cm_pre_commit: + next_phase = cm_commit; + break; + case cm_commit: + next_phase = cm_decide; + break; + } + + consensus_message n_msg = {next_phase, _currentQC.view_number, _currentQC.node, _currentQC}; + + vector finalizers; + + quorum_certificate qc = {next_phase, _currentQC.view_number, _currentQC.node, finalizers, fc::crypto::blslib::bls_signature("")}; + + _currentQC = qc; + + emit_new_phase(n_msg); + + //ilog("sent next phase message"); + + if (next_phase==cm_decide){ + + uint32_t block_height = n_msg.node.header.block_num(); + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + uint32_t distance_from_head = hbs->header.block_num() - block_height; + + ilog("decide decision has been reached on view #${view_number}. Block #${block_height} can be commited safely. Distance from head : ${distance_from_head}", + ("view_number", msg.view_number) + ("block_height", block_height) + ("distance_from_head", distance_from_head)); + + _qc_chain_state=finished_view; + + //if we're still producing, we can start a new view + if (std::find(_my_producers.begin(), _my_producers.end(), hbs->header.producer) != _my_producers.end()){ + create_new_view(*hbs); + } + + } + + } + else { + //uint32_t remaining = 14 - _currentQC.finalizers.size(); + + //ilog("need ${remaining} more votes to move to next phase", ("remaining", remaining)); + } + + } + else { + //ilog("WRONG already received vote for finalizer on this QC "); + + + } + + } + else { + //confirmation applies to another message + //ilog("WRONG QC"); + + } + + } + + void qc_chain::process_consensus_msg(consensus_message msg, bool self_leading){ + +/* ilog("got notified of consensus message: ${msg_type} for view ${view_number} ${self_leading}", + ("msg_type", msg.msg_type) + ("view_number", msg.view_number) + ("self_leading", self_leading));*/ + + auto itr = std::find_if(_processed_consensus_msgs.begin(), _processed_consensus_msgs.end(), [ &msg](consensus_message m){ + return m.msg_type == msg.msg_type && + m.view_number == msg.view_number && + m.node.digest_to_sign == msg.node.digest_to_sign; + }); + + if (itr!=_processed_consensus_msgs.end()){ + //ilog("WRONG already processed this message"); + return; //already processed + } + else { + //ilog("new consensus message. Processing..."); + _processed_consensus_msgs.push_back(msg); + + if (_processed_consensus_msgs.size()==100) _processed_consensus_msgs.erase(_processed_consensus_msgs.begin()); + + } + + //TODO validate message + + digest_type digest = get_digest_to_sign(msg.msg_type, msg.view_number, msg.node.digest_to_sign ); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + //if we're leading the view, reject the consensus message + //if (_qc_chain_state==leading_view) return; + + if (msg.justify.has_value()) { + + auto justify = msg.justify.value(); + + if (justify.finalizers.size() == 14){ + + fc::crypto::blslib::bls_public_key agg_pk = _private_key.get_public_key(); + + //verify QC + for (size_t i = 1 ; i < justify.finalizers.size();i++){ + agg_pk = fc::crypto::blslib::aggregate({agg_pk,_private_key.get_public_key()}); + } + + digest_type digest_j = get_digest_to_sign(justify.msg_type, justify.view_number, justify.node.digest_to_sign ); + std::vector hj = std::vector(digest_j.data(), digest_j.data() + 32); + +/* ilog("agg verification - key: ${agg_pk} hash: ${hj} sig: ${sig}", + ("agg_pk", agg_pk.to_string()) + ("hj", hj) + ("sig", justify.sig.to_string()));*/ + + bool ok = verify(agg_pk, hj, justify.sig); + + if (ok==false){ + //ilog("WRONG aggregate signature invalid"); + return; + } + + _view_number = msg.view_number; + + if (justify.msg_type == cm_pre_commit){ + _prepareQC = justify; + } + else if (justify.msg_type == cm_pre_commit){ + _lockedQC = justify; + } + } + else { + + //ilog("WRONG invalid consensus message justify argument"); + + return ; + } + } + + if (_qc_chain_state==initializing || _qc_chain_state==finished_view ) { + _view_number = msg.view_number; + _view_leader = msg.node.header.producer; + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + _view_finalizers = hbs->active_schedule.producers; + + _qc_chain_state=processing_view; + + } + + //if we received a commit decision and we are not also leading this round + if (msg.msg_type == cm_decide && self_leading == false){ + + uint32_t block_height = msg.node.header.block_num(); + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + uint32_t distance_from_head = hbs->header.block_num() - block_height; + + ilog("decide decision has been reached on view #${view_number}. Block #${block_height} can be commited safely. Distance from head : ${distance_from_head}", + ("view_number", msg.view_number) + ("block_height", block_height) + ("distance_from_head", distance_from_head)); + + //if current producer is not previous view leader, we must send a new_view message with our latest prepareQC + if (hbs->header.producer != _view_leader){ + //_view_number++; + _view_leader = hbs->header.producer; + _qc_chain_state=finished_view; + } + + return; + + } + else { + + auto p_itr = _my_producers.begin(); + + while(p_itr!= _my_producers.end()){ + + chain::account_name finalizer = *p_itr; + + auto itr = std::find_if(_view_finalizers.begin(), _view_finalizers.end(), [&](const auto& asp){ return asp.producer_name == finalizer; }); + + if (itr!= _view_finalizers.end()){ + + //ilog("Signing confirmation..."); + + fc::crypto::blslib::bls_signature sig = _private_key.sign(h);; + +/* ilog("signing confirmation message : ${h} - ${sig}", + ("h", h) + ("sig", sig.to_string()));*/ + + confirmation_message n_msg = {msg.msg_type, msg.view_number, msg.node, finalizer, sig}; + + //ilog("Sending confirmation message for ${finalizer}", ("finalizer", finalizer)); + + emit_confirm(n_msg); + + } + else { + //finalizer not in view schedule + //ilog("WRONG consensus ${finalizer}", ("finalizer", finalizer)); + + } + + p_itr++; + } + + } + } + + void qc_chain::emit_confirm(confirmation_message msg){ + + chain::controller& chain = _chain_plug->chain(); + +/* ilog("emit confirm ${msg_type}... view #${view_number} on block ${block_id}, digest to sign is : ${digest} ", + ("msg_type",msg.msg_type) + ("view_number",msg.view_number) + ("block_id",msg.node.header.calculate_id()) + ("digest",msg.node.digest_to_sign) );*/ + + confirmation_message_ptr ptr = std::make_shared(msg); + + chain.commit_confirmation_msg(ptr); + + process_confirmation_msg(msg, true); //notify ourselves, in case we are also the view leader + + } + + void qc_chain::emit_new_phase(consensus_message msg){ + + chain::controller& chain = _chain_plug->chain(); + + ilog("emit new phase ${msg_type}... view #${view_number} on block #${block_num}", + ("msg_type",msg.msg_type) + ("view_number",msg.view_number) + ("block_num",msg.node.header.block_num()) ); + + + //if (msg.justify.has_value()){ + + // auto justify = msg.justify.value(); + +/* ilog(" justify : view #${view_number} on block ${block_id}, digest to sign is : ${digest} ", + ("msg_type",justify.msg_type) + ("view_number",justify.view_number) + ("block_id",justify.node.header.calculate_id()) + ("digest",justify.node.digest_to_sign) );*/ + + //} + + consensus_message_ptr ptr = std::make_shared(msg); + + chain.commit_consensus_msg(ptr); + + process_consensus_msg(msg, true); //notify ourselves, in case we are also running finalizers + + } + + void qc_chain::on_new_view_interrupt(){ + + } + + void qc_chain::commit(block_header header){ + + } + + void qc_chain::print_state(){ + + ilog("QC CHAIN STATE : "); + + ilog(" view number : ${view_number}, view leader : ${view_leader}", + ("view_number", _view_number) + ("view_leader", _view_leader)); + + + if (_prepareQC.has_value()){ + + quorum_certificate prepareQC = _prepareQC.value(); + + ilog(" prepareQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", + ("msg_type", prepareQC.msg_type) + ("view_number", prepareQC.view_number) + ("block_num", prepareQC.node.header.block_num())); + + ilog(" finalizers : "); + + for (int i = 0 ; i < prepareQC.finalizers.size(); i++){ + ilog(" ${finalizer}", + ("finalizer", prepareQC.finalizers[i])); + } + + } + else { + ilog(" no prepareQC"); + } + + + if (_lockedQC.has_value()){ + + quorum_certificate lockedQC = _lockedQC.value(); + + ilog(" lockedQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", + ("msg_type", lockedQC.msg_type) + ("view_number", lockedQC.view_number) + ("block_num", lockedQC.node.header.block_num())); + + ilog(" finalizers : "); + + for (int i = 0 ; i < lockedQC.finalizers.size(); i++){ + ilog(" ${finalizer}", + ("finalizer", lockedQC.finalizers[i])); + } + + } + else { + ilog(" no _lockedQC"); + } + + ilog(" _currentQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", + ("msg_type", _currentQC.msg_type) + ("view_number", _currentQC.view_number) + ("block_num", _currentQC.node.header.block_num())); + + ilog(" finalizers : "); + + for (int i = 0 ; i < _currentQC.finalizers.size(); i++){ + ilog(" ${finalizer}", + ("finalizer", _currentQC.finalizers[i])); + } + + ilog(" _processed_confirmation_msgs count : ${count}", + ("count", _processed_confirmation_msgs.size())); + + ilog(" _processed_consensus_msgs count : ${count}", + ("count", _processed_consensus_msgs.size())); + +/* + + struct quorum_certificate { + + consensus_msg_type msg_type; + uint32_t view_number; + consensus_node node; + + vector finalizers; + bls_signature_type sig; + + }; + + std::set _my_producers; + + qc_chain_state _qc_chain_state; + + uint32_t _view_number; + chain::account_name _view_leader; + vector _view_finalizers; + + std::optional _prepareQC; + std::optional _lockedQC; + + fc::crypto::blslib::bls_private_key _private_key; + + quorum_certificate _currentQC; + + uint32_t _view_liveness_threshold; + + vector _processed_confirmation_msgs; + vector _processed_consensus_msgs; + +*/ + + } + +}} \ No newline at end of file From bc5957cf01f5dcc5cb016d0b073e91604bdadca9 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 30 Dec 2022 15:56:32 +0000 Subject: [PATCH 006/151] Added pseudo code file --- hostuff-pseudo.txt | 664 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 664 insertions(+) create mode 100644 hostuff-pseudo.txt diff --git a/hostuff-pseudo.txt b/hostuff-pseudo.txt new file mode 100644 index 0000000000..1d74a11e4d --- /dev/null +++ b/hostuff-pseudo.txt @@ -0,0 +1,664 @@ +/* + + Antelope + Hotstuff = Roasted Antelope + + Roasted Antelope is a proposal for an upgrade to the Antelope consensus model, based on the Hotstuff protocol. This document defines extended pseudocode for this upgrade, and should be relatively straightforward to plug into the existing Antelope codebase. + + Notes: This pseudocode is based on algorithms 4 (safety) & 5 (liveness) of the "HotStuff: BFT Consensus in the Lens of Blockchain" paper. + + There are a few minor modifications to the pacemaker algorithm implementation, allowing to decompose the role of block producer into the 3 sub-roles of block proposer, block finalizer and view leader. + + This pseudocode handles each role separately. A single entity may play multiple roles. + + This pseudocode also covers changes to the finalizer set, which include transition from and into dual_set mode. + + Under dual_set mode, the incumbent and the incoming finalizer sets are jointly confirming views. + + As is the case with the algorithm 4, the notion of view is almost completely decoupled from the safety protocol, and is aligned to the liveness protocol instead. + +*/ + +// Data structures + +//evolved from producer_schedule +struct schedule(){ + + //currently, block_proposers, block_finalizers and view_leaders sets are block producers. A future upgrade can further define the selection process for each of these roles, and result in distinct sets of variable size without compromising the protocol's safety + + block_proposers = [...]; + + block_finalizers = [...] //current / incumbent block finalizers set + incoming_block_finalizers = [...]; //incoming block finalizers set, null if operating in single_set mode + + view_leaders = [...]; + + current_leader //defined by pacemaker, abstracted; + current_proposer //defined by pacemaker, abstracted; + + get_proposer(){return current_proposer} ; + get_leader(){return current_leader} ; + + //returns a list of incumbent finalizers + get_finalizers(){return block_finalizers} ; + + //returns a combined list of incoming block_finalizers + get_incoming_finalizers(){return incoming_block_finalizers} ; + +} + +//quorum certificate +struct qc(){ + + //block candidate ID, acts as node message + block_id + + //aggregate signature of finalizers part of this qc + agg_sig + + //data structure which includes the list of signatories included in the aggregate, (for easy aggregate signature verification). It can also support dual_set finalization mode + sig_bitset + + //aggregate signature of incoming finalizers part of this qc, only present if we are operating in dual_set finalization mode + incoming_agg_sig; + + //data structure which includes the list of incoming signatories included in the aggregate (for easy verification), only present if we are operating in dual_set finalization mode + incoming_sig_bitset; + + //get block height from block_id + get_height() = ; //abstracted [...] + + //check if a quorum of valid signatures from active (incumbent) finalizers has been met according to me._threshold + quorum_met() = ; //abstracted [...] + + //check if a quorum of valid signatures from both active (incumbent) finalizers AND incoming finalizers has been met. Quorums are calculated for each of the incumbent and incoming sets separately, and both sets must independently achieve quorum for this function to return true + extended_quorum_met() = ;//abstracted [...] + +} + +//proposal +struct block_candidate(){ + + //previous field of block header + parent + + //list of actions to be executed + cmd + + //qc justification for this block + justify + + //block id, which also contains block height + block_id + + //return block height from block_id + get_height() = ; //abstracted [...]; + + //return the actual block this candidate wraps around, including header + transactions / actions + get_block() = ; //abstracted [...]; + +} + +//available msg types +enum msg_type { + new_view //used when leader rotation is required + new_block //used when proposer is different from leader + qc //progress + vote //vote by replicas +} + +// Internal book keeping variables + +//Hotstuff protocol + +me._v_height; //height of last voted node + +me._b_lock; //locked block_candidate +me._b_exec; //last committed block_candidate +me._b_leaf; //current block_candidate + +me._high_qc; //highest known QC + +me._dual_set_height; //dual set finalization mode active as of this block height, -1 if operating in single_set mode. A finalizer set change is successfully completed when a block is committed at the same or higher block height + +//chain data + +me._b_temporary; //temporary storage of received block_candidates. Pruning rules are abstracted + +me._schedule //current block producer schedule, mapped to new structure + + +//global configuration + +me._block_interval; //expected block time interval, default is 0.5 second +me._blocks_per_round; //numbers of blocks per round, default is 12 + +me._threshold; //configurable quorum threshold + + +//network_plugin protocol hooks and handlers + +//generic network message generation function +network_plugin.new_message(type, ...data){ + + new_message.type = type; + new_message[...] = ...data; + + return new_message; +} + +network_plugin.broadcast(msg){ + + //broadcasting to other nodes, replicas, etc. + + //nodes that are not part of consensus making (not proposer, finalizer or leader) relay consensus messages, but take no action on them + + //abstracted [...] + +} + +//on new_block message received event handler (coming from a proposer that is not leader) +network_plugin.on_new_block_received(block){ + + //abstracted [...] + + pacemaker.on_beat(block); //check if we are leader and need to create a view for this block + +} + +//on vote received event handler +network_plugin.on_vote_received(msg){ + + //abstracted [...] + + hotstuff.on_vote_received(msg); + +} + + + + + +//Pacemaker algorithm, regulating liveness + + +//on_beat(block) is called in the following cases : +//1) As a block proposer, when we generate a block_candidate +//2) As a view leader, when we receive a block_candidate from a proposer +pacemaker.on_beat(block){ + + am_i_proposer = me._schedule.get_proposer() == me; //am I proposer? + am_i_leader = me._schedule.get_leader() == me; //am I leader? + + if (!am_i_proposer && !am_i_leader) return; //replicas don't have to do anything here, unless they are also leader and/or proposer + + block_candidate = new_proposal_candidate(block); + + //if i'm the leader + if (am_i_leader){ + + if (!am_i_proposer){ + + //block validation hook + //abstracted [...] + + //If I am the leader but not the proposer, check if proposal is safe. + if(!hotstuff.is_node_safe(block_candidate)) return; + + } + + me._b_leaf = block_candidate; + + } + + if (am_i_leader) msg = new_message(qc, block_candidate); //if I'm leader, send qc message + else msg = new_message(new_block, block_candidate); //if I'm only proposer, send new_block message + + network_plugin.broadcast(msg); //broadcast message + +} + +//update high qc +pacemaker.update_high_qc(new_high_qc){ + + // if new high QC is higher than current, update to new + if (new_high_qc.get_height()>me._high_qc.block.get_height()){ + + me._high_qc = new_high_qc; + me._b_leaf = me._b_temporary.get(me._high_qc.block_id); + + } + +} + +pacemaker.on_msg_received(msg){ + + //p2p message relay logic + //abstracted [...] + + if (msg.type == new_view){ + pacemaker.update_high_qc(msg.high_qc); + } + else if (msg.type == qc){ + hotstuff.on_proposal_received(msg); + } + else if (msg.type == vote){ + hotstuff.on_vote_received(msg); + } +} + +//returns the proposer, according to schedule +pacemaker.get_proposer(){ + return schedule.get_proposer(); //currently active producer is proposer +} + +//returns the leader, according to schedule +pacemaker.get_leader(){ + return schedule.get_leader(); //currently active producer is leader +} + + +/* + + Corresponds to onNextSyncView in hotstuff paper. Handles both leader rotations as well as timeout if leader fails to progress + + Note : for maximum liveness, on_leader_rotate() should be called by replicas as early as possible when either : + + 1) no more blocks are expected before leader rotation occurs (eg: after receiving the final block expected from the current leader before the handoff) OR + + 2) if we reach (me._block_interval * (me._blocks_per_round - 1)) time into a specific view, and we haven't received the expected second to last block for this round. + + In scenarios where liveness is maintained, this relieves an incoming leader from having to wait until it has received n - f new_view messages at the beginning of a new view since it will already have the highest qc. + + In scenarios where liveness has been lost due to f + 1 faulty replicas, progress is impossible, so the safety rule rejects attempts at creating a qc until liveness has been restored. + +*/ + +pacemaker.on_leader_rotate(){ + + msg = new_message(new_view, me._high_qc); //add highest qc + + network_plugin.broadcast(msg); //broadcast message + +} + + + +//producer_plugin hook for block generation + +//on block produced event handler (block includes signature of proposer) +producer_plugin.on_block_produced(block){ + + //generate a new block extending from me._b_leaf + //abstracted [...] + + /* + + Include the highest qc we recorded so far. Nodes catching up or light clients have a proof that the block referred to as high qc is irreversible. + + We can merge the normal agg_sig / sig_bitset with the incoming_agg_sig / incoming_sig_bitset if the qc was generated in dual_set mode before we include the qc into the block, to save space + + */ + + block.qc = me._high_qc; + + pacemaker.on_beat(block); + +} + + + +//Hotstuff algorithm, regulating safety + +hotstuff.new_proposal_candidate(block) { + + b.parent = block.header.previous; + b.cmd = block.actions; + b.justify = me._high_qc; //or null if no _high_qc upon activation or chain launch + b.block_id = block.header.block_id(); + + //return block height from block_id + b.get_height() = //abstracted [...]; + + return b; +} + +//safenode predicate +hotstuff.is_node_safe(block_candidate){ + + monotony_check = false; + safety_check = false; + liveness_check = false; + + if (block_candidate.get_height() > me._v_height){ + monotony_check = true; + } + + if (me._b_lock){ + + //Safety check : check if this proposal extends the chain I'm locked on + if (extends(block_candidate, me._b_lock)){ + safety_check = true; + } + + //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. + if (block_candidate.justify.get_height() > me._b_lock.get_height())){ + liveness_check = true; + } + + } + else { + + //if we're not locked on anything, means the protocol just activated or chain just launched + liveness_check = true; + safety_check = true; + } + + //Lemma 2 + return monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully + +} + +//verify if b_descendant extends a branch containing b_ancestor +hotstuff.extends(b_descendant, b_ancestor){ + + //in order to qualify as extending b_ancestor, b_descendant must descend from b_ancestor + //abstracted [...] + + return true || false; + +} + +//creates or get, then return the current qc for this block candidate +hotstuff.create_or_get_qc(block_candidate){ + + //retrieve or create unique QC for this stage, primary key is block_id + //abstracted [...] + + return qc; // V[] + +} + +//add a signature to a qc +hotstuff.add_to_qc(qc, finalizer, sig){ + + //update qc reference + + // V[b] + + if (schedule.get_finalizers.contains(finalizer) && !qc.sig_bitset.contains(finalizer)){ + qc.sig_bitset += finalizer; + qc.agg_sig += sig; + } + + if (schedule.get_incoming_finalizers.contains(finalizer) && !qc.incoming_sig_bitset.contains(finalizer)){ + qc.incoming_sig_bitset += finalizer; + qc.incoming_agg_sig += sig; + } + +} + +//when we receive a proposal +hotstuff.on_proposal_received(msg){ + + //block candidate validation hook (check if block is valid, etc.), return if not + //abstracted [...] + + /* + + First, we verify if we have already are aware of the proposal, and if the QC was updated + + */ + + //Lemma 1 + stored_block = me._b_temporary.get(msg.block_candidate.block_id); + + //If we already have this proposal, we return, else we store it and we continue + if (stored_block) { + if (stored_block.justify.agg_sig == msg.block_candidate.justify.agg_sig) return; + } + else me._b_temporary.add(msg.block_candidate); //new block + + //check if I'm finalizer, in which case I will optionally sign and update my internal state + + am_i_finalizer = get_finalizers.contains(me) || get_incoming_finalizers(me); + + //if I am a finalizer for this proposal, test safenode predicate for possible vote + if (am_i_finalizer && hotstuff.is_node_safe(msg.block_candidate)){ + + me._v_height = msg.block_candidate.get_height(); + + /* + Sign message. + + In Hotstuff, we need to sign a tuple of (msg.view_type, msg.view_number and msg.node). + + In our implementation, the view_type is generic, and the view_number and message node are both contained in the block_id. + + Therefore, we can ensure uniqueness by replacing the view_type with msg.block_candidate.justify.agg_sig. + + The digest to sign now becomes the tuple (msg.block_candidate.justify.agg_sig, msg.block_candidate.block_id). + + */ + + sig = = _dual_set_height){ + quorum_met = qc.extended_quorum_met(); + } + else quorum_met = qc.quorum_met(); + + if (quorum_met){ + + pacemaker.update_high_qc(qc); + + } + +} + +//internal state update of replica +hotstuff.update(block_candidate){ + + b_new = block_candidate; + + b2 = me._b_temporary.get(b_new.justify.block_id); //first phase, prepare + b1 = me._b_temporary.get(b2.justify.block_id); //second phase, precommit + b = me._b_temporary.get(b1.justify.block_id); //third phase, commit + + //if a proposed command for the transition of the finalizer set is included in b_new's commands (for which we don't have a qc). Nothing special to do, but can be a useful status to be aware of for external APIs. + new_proposed_transition = ; //abstracted [...] + + //if a transition command of the finalizer set is included in b2's commands (on which we now have a qc), we now know n - f replicas approved the transition. If no other transition is currently pending, it becomes pending. + new_pending_transition = ; //abstracted [...] + + if (new_pending_transition){ + me._dual_set_height = b_new.get_height() + 1; //if this block proves a quorum on a finalizer set transition, we now start using the extended_quorum_met() predicate until the transition is successfully completed + } + + //precommit phase on b2 + pacemaker.update_high_qc(block_candidate.justify); + + if (b1.get_height() > me._b_lock.get_height()){ + me._b_lock = b1; //commit phase on b1 + } + + //direct parent relationship verification + if (b2.parent == b1 && b1.parent == b){ + + //if we are currently operating in dual set mode reaching this point, and the block we are about to commit has a height higher or equal to me._dual_set_height, it means we have reached extended quorum on a view ready to be committed, so we can transition into single_set mode again, where the incoming finalizer set becomes the active finalizer set + if (me._dual_set_height != -1 && b.get_height() >= me._dual_set_height){ + + //sanity check to verify quorum on justification for b (b1), should always evaluate to true + if (b1.justify.extended_quorum_met()){ + + //reset internal state to single_set mode, with new finalizer set + me._schedule.block_finalizers = me_.schedule.incoming_finalizers; + me_.schedule.incoming_finalizers = null; + me._dual_set_height = -1; + + } + + } + + hotstuff.commit(b); + + me._b_exec = b; //decide phase on b + + } + +} + +//commit block and execute its actions against irreversible state +hotstuff.commit(block_candidate){ + + //check if block_candidate already committed, if so, return because there is nothing to do + + //can only commit newer blocks + if (me._b_exec.get_height() < block_candidate.get_height()){ + + parent_b = _b_temporary.get(block_candidate.parent); + + hotstuff.commit(parent_b); //recursively commit all non-committed ancestor blocks sequentially first + + //execute block cmd + //abstracted [...] + + } +} + + +/* + + Proofs : + + Safety : + + Lemma 1. Let b and w be two conflicting block_candidates such that b.get_height() = w.get_height(), then they cannot both have valid quorum certificates. + + Proof. Suppose they can, so both b and w receive 2f + 1 votes, among which there are at least f + 1 honest replicas + voting for each block_candidate, then there must be an honest replica that votes for both, which is impossible because b and w + are of the same height. + + This is enforced by the line labeled "Lemma 1". + + Lemma 2. Let b and w be two conflicting block_candidates. Then they cannot both become committed, each by an honest replica. + + Proof. We prove this lemma by contradiction. Let b and w be two conflicting block_candidates at different heights. + Assume during an execution, b becomes committed at some honest replica via the QC Three-Chain b. + + For this to happen, b must be the parent and justification of b1, b1 must be the parent and justification of b2 and b2 must be the justification of a new proposal b_new. + + Likewise w becomes committed at some honest replica via the QC Three-Chain w. + + For this to happen, w must be the parent and justification of w1, w1 must be the parent and justification of w2 and w2 must be the justification of a new proposal w_new. + + By lemma 1, since each of the block_candidates b, b1, b2, w, w1, w2 have QCs, then without loss of generality, we assume b.get_height() > w2.get_height(). + + We now denote by qc_s the QC for a block_candidate with the lowest height larger than w2.get_height(), that conflicts with w. + + Assuming such qc_s exists, for example by being the justification for b1. Let r denote a correct replica in the intersection of w_new.justify and qc_s. By assumption of minimality of qc_s, the lock that r has on w is not changed before qc_s is formed. Now, consider the invocation of on_proposal_received with a message carrying a conflicting block_candidate b_new such that b_new.block_id = qc_s.block_id. By assumption, the condition on the lock (see line labeled "Lemma 2") is false. + + On the other hand, the protocol requires t = b_new.justifty to be an ancestor of b_new. By minimality of qc_s, t.get_height() <= w2.get_height(). Since qc_s.block_id conflicts with w.block_id, t cannot be any of w, w1 or w2. Then, t.get_height() < w.get_height() so the other half of the disjunct is also false. Therefore, r will not vote for b_new, contradicting the assumption of r. + + Theorem 3. Let cmd1 and cmd2 be any two commands where cmd1 is executed before cmd2 by some honest replica, then any honest replica that executes cmd2 must execute cm1 before cmd2. + + Proof. Denote by w the node that carries cmd1, b carries cmd2. From Lemma 1, it is clear the committed nodes are at distinct heights. Without loss of generality, assume w.get_height() < b.height(). The commitment of w and b are handled by commit(w1) and commit(b1) in update(), where w is an ancestor of w1 and b is an ancestor of b1. According to Lemma 2, w1 must not conflict with b1, so w does not conflict with b. Then, w is an ancestor of b, and when any honest replica executes b, it must first execute w by the recursive logic in commit(). + + Liveness : + + In order to prove liveness, we first show that after GST, there is a bounded duration T_f such that if all correct replicas remain in view v during T_f and the leader for view v is correct, then a decision is reached. We define qc_1 and qc_2 as matching QCs if qc_1 and qc_2 are both valid and qc_1.block_id = qc_2.block_id. + + Lemma 4. If a correct replica is locked such that me._b_lock.justify = generic_qc_2, then at least f + 1 correct replicas voted for some generic_qc_1 matching me._b_lock.justify. + + Proof. Suppose replica r is locked on generic_qc_2. Then, (n-f) votes were cast for the matching generic_qc_1 in an earlier phase (see line labeled "Lemma 4"), out of which at least f + 1 were from correct replicas. + + Theorem 5. After GST, there exists a bounded time period T_f such that if all correct replicas remain in view v during + T_f and the leader for view v is correct, then a decision is reached. + + Proof. Starting in a new view, the leader has collected (n − f) new_view or vote messages and calculates its high_qc before + broadcasting a qc message. Suppose among all replicas (including the leader itself), the highest kept lock + is me._b_lock.justify = generic_qc_new_2. + + By Lemma 4, we know there are at least f + 1 correct replicas that voted for a generic_qc_new_1 matching generic_qc_new_2, and have already sent them to the leader in their new_view or vote messages. Thus, the leader must learn a matching generic_qc_new_2 in at least one of these new_view or vote messages and use it as high_qc in its initial qc message for this view. By the assumption, all correct replicas are synchronized in their view and the leader is non-faulty. Therefore, all correct replicas will vote at a specific height, since in is_node_safe(), the condition on the line labeled "Liveness check" is satisfied. This is also the case if the block_id in the message conflicts with a replica’s stale me._b_lock.justify.block_id, such that the condition on the line labeled "Safety check" is evaluated to false. + + Then, after the leader has a valid generic_qc for this view, all replicas will vote at all the following heights, leading to a new commit decision at every step. After GST, the duration T_f for the steps required to achieve finality is of bounded length. + + The protocol is Optimistically Responsive because there is no explicit “wait-for-∆” step, and the logical disjunction in is_node_safe() is used to override a stale lock with the help of the Three-Chain paradigm. + + Accountability and finality violation : + + Let us define b_descendant as a descendant of b_root, such that hotstuff.extends(b_descendant, b_root) returns true. + + Suppose b_descendant's block header includes a high_qc field representing a 2f + 1 vote on b_root. When we become aware of a new block where the high_qc points to b_descendant or to one of b_descendant's descendants, we know b_root, as well as all of b_root's ancestors, have been committed and are final. + + Theorem 6. Let b_root and w_root be two conflicting block_candidates of the same height, such that hotstuff.extends(b_root, w_root) and hotstuff.extends(w_root, b_root) both return false, and that b_root.get_height() == w_root.get_height(). Then they cannot each have a valid quorum certificate unless a finality violation has occurred. In the case of such finality violation, any party in possession of b_root and w_root would be able to prove complicity or exonerate block finalizers having taken part or not in causing the finality violation. + + Proof. Let b_descendant and w_descendant be descendants of respectively b_root and w_root, such that hotstuff.extends(b_descendant, b_root) and hotstuff.extends(w_descendant, w_root) both return true. + + By Lemma 1, we know that a correct replica cannot sign two conflicting block candidates at the same height. + + For each of b_root and w_root, we can identify and verify the signatures of finalizers, by ensuring the justification's agg_sig matches the aggregate key calculated from the sig_bitset and the schedule. + + Therefore, for b_root and w_root to both be included as qc justification into descendant blocks, at least one correct replica must have signed two vote messages on conflicting block candidates at the same height, which is impossible due to the check performed on the line with comment "Lemma 1", unless a finality violation occurred. + + For a finality violation to occur, the intersection of the finalizers that have voted for both b_root and w_root, as evidenced by the high_qc of b_descendant and w_descendant must represent a minimum of f + 1 faulty nodes. + + By holding otherwise valid blocks where a qc for b_root and w_root exist, the finality violation can be proved trivially, simply by calculating the intersection and the symmetrical difference of the finalizer sets having voted for these two proposals. The finalizers contained in the intersection can therefore be blamed for the finality violation. The symmetric difference of finalizers that have voted for either proposal but not for both can be exonerated from wrong doing, thus satisfying the Accountability property requirement. + + Finalizer set transition (safety proof) : + + Replicas can operate in either single_set or dual_set validation mode. In single_set mode, quorum is calculated and evaluated only for the active finalizer set. In dual_set mode, independant quorums are calculated over each of the active (incumbent) finalizer set and the incoming finalizer set, and are evaluated separately. + + Let us define active_set as the active finalizer set, as determined by the pacemaker at any given point while a replica is operating in single_set mode. The active_set is known to all active replicas that are in sync. While operating in single_set mode, verification of quorum on proposals is achieved through the use of the active_set.quorum_met() predicate. + + Let us define incumbent_set and incoming_set as, respectively, the previously active_set and a new proposed set of finalizers, starting at a point in time when a replica becomes aware of a quorum on a block containing a finalizer set transition proposal. This triggers the transition into dual_set mode for this replica. + + As the replica is operating in dual_set mode, the quorum_met() predicate used in single_set mode is temporarily replaced with the extended_quorum_met() predicate, which only returns true if (incumbent_set.quorum_met() AND incoming_set.quorum_met()). + + As we demonstrated in Lemma 1, Lemma 2 and Theorem 3, the protocol is safe when n - f correct replicas achieve quorum on proposals. + + Therefore, no safety is lost as we are transitioning into dual_set mode, since this transition only adds to the quorum constraints guaranteeing safety. However, this comes at the cost of decreased plausible liveness, because of the additional constraint of also requiring the incoming finalizer set to reach quorum in order to progress. //todo : discuss possible recovery from incoming finalizer set liveness failure + + Theorem 7. A replica can only operate in either single_set mode or in dual_set mode. While operating in dual_set mode, the constraints guaranteeing safety of single_set mode still apply, and thus the dual_set mode constraints guaranteeing safety can only be equally or more restrictive than when operating in single_set mode. + + Proof. Suppose a replica is presented with a proposal b_new, which contains a qc on a previous proposal b_old such that hotstuff.extends(b_new, b_old) returns true, and that the replica could operate in both single_set mode and dual_set mode at the same time, in such a way that active_set == incumbent_set and that an unknown incoming_set also exists. + + As it needs to verify the qc, the replica invokes both quorum_met() and extended_quorum_met() predicates. + + It follows that, since active_set == incumbent_set, and that active_set.quorum_met() is evaluated in single_set mode, and incumbent_set.quorum_met() is evaluated as part of the extended_quorum_met() predicate in dual_set mode, the number of proposals where (incumbent_set.quorum_met() AND incoming_set.quorum_met()) is necessarily equal or smaller than the number of proposals where active_set.quorum_met(). In addition, any specific proposal where active_set.quorum_met() is false would also imply (incumbent_set.quorum_met() AND incoming_set.quorum_met()) is false as well. + + Therefore, the safety property is not weakened while transitioning into dual_set mode. + +*/ + + + + From a0007c212be5491284ac4d227941cdac6e75a7ad Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sat, 31 Dec 2022 13:13:09 +0000 Subject: [PATCH 007/151] Updated process_propsal to verify block height --- .../eosio/producer_plugin/qc_chain.hpp | 2 +- plugins/producer_plugin/qc_chain.cpp | 95 +++++++++++-------- 2 files changed, 59 insertions(+), 38 deletions(-) diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp index 8fc6b9ee58..8fbd3c4e95 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp @@ -43,7 +43,7 @@ namespace eosio { namespace chain { name get_leader(); name get_incoming_leader(); - bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, bool dual_set_mode); + bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal, bool dual_set_mode); std::vector get_finalizers(); diff --git a/plugins/producer_plugin/qc_chain.cpp b/plugins/producer_plugin/qc_chain.cpp index 55bff07ee1..00e7f7c821 100644 --- a/plugins/producer_plugin/qc_chain.cpp +++ b/plugins/producer_plugin/qc_chain.cpp @@ -9,6 +9,22 @@ #include #include + +//todo list notes : + +// add QC to block header +// +// add optimistically responsive mode +// +// under optimistically responsive mode, proposal height also includes a phase counter. +// +// 0 for proposal (prepare phase) +// 1 for prepareQC (precommit phase) +// 2 for precommitQC (commit phase) +// 3 for commitQC (decide phase)). +// +// The phase counter extends the block height for the monotony check, so that a proposal where block height equals 2,131,059 and is in precommit phase (prepareQC reached) would have a view number of (2131059, 2). If the proposal is accepted and completes the commit phase , the view number becomes (2131059, 3) which respects the monotony rule + namespace eosio { namespace chain { using boost::multi_index_container; using namespace boost::multi_index; @@ -58,7 +74,7 @@ namespace eosio { namespace chain { tag, BOOST_MULTI_INDEX_MEMBER(eosio::chain::quorum_certificate,block_id_type,block_id) >, - ordered_non_unique< + ordered_unique< tag, BOOST_MULTI_INDEX_CONST_MEM_FUN(eosio::chain::quorum_certificate,uint32_t,block_num) > @@ -72,7 +88,7 @@ namespace eosio { namespace chain { tag, BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,block_id_type,block_id) >, - ordered_non_unique< + ordered_unique< tag, BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint32_t,block_num) > @@ -155,50 +171,49 @@ namespace eosio { namespace chain { return b; } - bool _quorum_met(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig){ + bool _quorum_met(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ - //ilog("evaluating if _quorum_met"); if (finalizers.size() != _threshold){ - //ilog("finalizers.size() ${size}", ("size",finalizers.size())); return false; - } - //ilog("correct threshold"); + ilog("correct threshold of finalizers. Verifying signatures"); - /* fc::crypto::blslib::bls_public_key agg_key; + fc::crypto::blslib::bls_public_key agg_key; - for (name f : finalizers) { + for (int i = 0; i < finalizers.size(); i++) { - auto itr = es.bls_pub_keys.find(f); + //adding finalizer's key to the aggregate pub key + if (i==0) agg_key = _private_key.get_public_key(); + else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); - if (itr==es.bls_pub_keys.end()) return false; + } - agg_key = fc::crypto::blslib::aggregate({agg_key, itr->second }); + fc::crypto::blslib::bls_signature justification_agg_sig; - } + if (proposal.justify.has_value()) justification_agg_sig = proposal.justify.value().active_agg_sig; - std::vector msg = std::vector(block_id.data(), block_id.data() + 32); + digest_type digest = get_digest_to_sign(justification_agg_sig, proposal.block_id); - bool ok = fc::crypto::blslib::verify(agg_key, msg, agg_sig); + std::vector h = std::vector(digest.data(), digest.data() + 32); - return ok; */ + bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); - return true; //temporary + return ok; } - bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, bool dual_set_mode){ + bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal, bool dual_set_mode){ if ( dual_set_mode && qc.incoming_finalizers.has_value() && qc.incoming_agg_sig.has_value()){ - return _quorum_met(schedule, qc.active_finalizers, qc.active_agg_sig) && _quorum_met(schedule, qc.incoming_finalizers.value(), qc.incoming_agg_sig.value()); + return _quorum_met(schedule, qc.active_finalizers, qc.active_agg_sig, proposal) && _quorum_met(schedule, qc.incoming_finalizers.value(), qc.incoming_agg_sig.value(), proposal); } else { - return _quorum_met(schedule, qc.active_finalizers, qc.active_agg_sig); + return _quorum_met(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); } } @@ -210,13 +225,6 @@ namespace eosio { namespace chain { ilog("qc chain initialized -> my producers : "); - auto itr = _my_producers.begin(); - while ( itr != _my_producers.end()){ - - ilog("${producer}", ("producer", *itr)); - - itr++; - } } @@ -303,15 +311,22 @@ namespace eosio { namespace chain { ilog("=== Process proposal #${block_num} ${block_id}", ("block_id", msg.block_id)("block_num", msg.block_num())); - auto itr = _proposal_store.get().find( msg.block_id ); + bool skip_sign = false; - if (itr != _proposal_store.get().end()){ + auto itr = _proposal_store.get().find( msg.block_num() ); - ilog("duplicate proposal"); - - return; //duplicate + //if we already received a proposal at this block height + if (itr != _proposal_store.get().end()){ + + //we check if it is the same proposal we already received. If it is, it is a duplicate message and we don't have anything else to do. If it isn't, it may indicate double signing + //todo : store conflicting proposals for accountability purposes + if (itr->block_id != msg.block_id){ + + ilog("conflicting proposal at block height : ${block_num} ", ("block_num", msg.block_num())); - //if (itr->justify.has_value() && msg.justify.has_value() && itr->justify.value().active_agg_sig == msg.justify.value().active_agg_sig) return; + } + + skip_sign = true; //duplicate } else { @@ -337,7 +352,7 @@ namespace eosio { namespace chain { //ilog("am_finalizer : ${am_finalizer}", ("am_finalizer", am_finalizer)); //ilog("node_safe : ${node_safe}", ("node_safe", node_safe)); - bool signature_required = am_finalizer && node_safe; + bool signature_required = !skip_sign && am_finalizer && node_safe; //if I am a finalizer for this proposal, test safenode predicate for possible vote @@ -420,7 +435,13 @@ namespace eosio { namespace chain { if (itr!=_qc_store.get().end()){ - bool quorum_met = is_quorum_met(*itr, _schedule, false); + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( msg.block_id ); + + if (p_itr==_proposal_store.get().end()){ + ilog("couldn't find proposal"); + } + + bool quorum_met = is_quorum_met(*itr, _schedule, *p_itr, false); if (!quorum_met){ @@ -429,7 +450,7 @@ namespace eosio { namespace chain { qc.active_agg_sig = fc::crypto::blslib::aggregate({qc.active_agg_sig, msg.sig }); }); - quorum_met = is_quorum_met(*itr, _schedule, false); + quorum_met = is_quorum_met(*itr, _schedule, *p_itr, false); if (quorum_met){ @@ -643,7 +664,7 @@ namespace eosio { namespace chain { block_timestamp_type next_block_time = current_block_header.timestamp.next(); - ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", + ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", ("old_timestamp", current_block_header.timestamp)("new_timestamp", current_block_header.timestamp.next())); producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); From 5925d0a5949b4b255eb97054504e637936f0eabb Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sat, 31 Dec 2022 13:14:53 +0000 Subject: [PATCH 008/151] Updated pseudo code --- hostuff-pseudo.txt | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/hostuff-pseudo.txt b/hostuff-pseudo.txt index 1d74a11e4d..997719a74f 100644 --- a/hostuff-pseudo.txt +++ b/hostuff-pseudo.txt @@ -405,25 +405,25 @@ hotstuff.on_proposal_received(msg){ /* - First, we verify if we have already are aware of the proposal, and if the QC was updated + First, we verify if we have already are aware of a proposal at this block height */ //Lemma 1 - stored_block = me._b_temporary.get(msg.block_candidate.block_id); - - //If we already have this proposal, we return, else we store it and we continue - if (stored_block) { - if (stored_block.justify.agg_sig == msg.block_candidate.justify.agg_sig) return; - } - else me._b_temporary.add(msg.block_candidate); //new block + stored_block = me._b_temporary.get(msg.block_candidate.get_height()); //check if I'm finalizer, in which case I will optionally sign and update my internal state am_i_finalizer = get_finalizers.contains(me) || get_incoming_finalizers(me); - //if I am a finalizer for this proposal, test safenode predicate for possible vote - if (am_i_finalizer && hotstuff.is_node_safe(msg.block_candidate)){ + skip_sign = false; + + //If we already have a proposal at this height, we must not double sign so we skip signing, else we store the proposal and and we continue + if (stored_block) skip_sign = true; + else me._b_temporary.add(msg.block_candidate); //new proposal + + //if I am a finalizer for this proposal and allowed to sign, test safenode predicate for possible vote + if (am_i_finalizer && !skip_sign && hotstuff.is_node_safe(msg.block_candidate)){ me._v_height = msg.block_candidate.get_height(); @@ -432,9 +432,9 @@ hotstuff.on_proposal_received(msg){ In Hotstuff, we need to sign a tuple of (msg.view_type, msg.view_number and msg.node). - In our implementation, the view_type is generic, and the view_number and message node are both contained in the block_id. + In our implementation, the view_type is generic, and the view_number is contained in the block_id, which is also the message. - Therefore, we can ensure uniqueness by replacing the view_type with msg.block_candidate.justify.agg_sig. + Therefore, we can ensure uniqueness by replacing the view_type part of the tuple with msg.block_candidate.justify.agg_sig. The digest to sign now becomes the tuple (msg.block_candidate.justify.agg_sig, msg.block_candidate.block_id). @@ -567,7 +567,7 @@ hotstuff.commit(block_candidate){ voting for each block_candidate, then there must be an honest replica that votes for both, which is impossible because b and w are of the same height. - This is enforced by the line labeled "Lemma 1". + This is enforced by the function labeled "Lemma 1". Lemma 2. Let b and w be two conflicting block_candidates. Then they cannot both become committed, each by an honest replica. @@ -627,7 +627,7 @@ hotstuff.commit(block_candidate){ For each of b_root and w_root, we can identify and verify the signatures of finalizers, by ensuring the justification's agg_sig matches the aggregate key calculated from the sig_bitset and the schedule. - Therefore, for b_root and w_root to both be included as qc justification into descendant blocks, at least one correct replica must have signed two vote messages on conflicting block candidates at the same height, which is impossible due to the check performed on the line with comment "Lemma 1", unless a finality violation occurred. + Therefore, for b_root and w_root to both be included as qc justification into descendant blocks, at least one correct replica must have signed two vote messages on conflicting block candidates at the same height, which is impossible due to the checks performed in the function with comment "Lemma 1". Such an event would be a finality violation. For a finality violation to occur, the intersection of the finalizers that have voted for both b_root and w_root, as evidenced by the high_qc of b_descendant and w_descendant must represent a minimum of f + 1 faulty nodes. @@ -661,4 +661,3 @@ hotstuff.commit(block_candidate){ - From 41c99dae60719922bbc0d0b5e4944c3ce8fb5e18 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Wed, 8 Mar 2023 12:30:00 +0000 Subject: [PATCH 009/151] Event driven hotstuff core functionalities --- .../chain/include/eosio/chain/hotstuff.hpp | 142 +- libraries/libfc/test/CMakeLists.txt | 6 +- .../eosio/producer_plugin/qc_chain.hpp | 101 +- plugins/producer_plugin/qc_chain.cpp | 1426 ++++++++--------- 4 files changed, 680 insertions(+), 995 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 11062a0e1a..6098649751 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -23,6 +23,10 @@ namespace eosio { namespace chain { return fc::endian_reverse_u32(block_id._hash[0]); } + static uint64_t compute_height(uint32_t block_height, uint32_t phase_counter){ + return (uint64_t{block_height} << 32) | phase_counter; + } + struct extended_schedule { producer_authority_schedule producer_schedule; @@ -31,154 +35,71 @@ namespace eosio { namespace chain { }; -/* struct qc_height { - - uint32_t block_height; - uint8_t phase; - - bool operator == (const qc_height& rhs) { - if (block_height != rhs.block_height) return false; - if (phase != rhs.phase) return false; - return true; - } - - bool operator != (const qc_height& rhs) { - if (block_height != rhs.block_height) return true; - if (phase != rhs.phase) return true; - return false; - } - - bool operator<(const qc_height& rhs) { - if (block_height < rhs.block_height) return true; - else if (block_height == rhs.block_height){ - if (phase < rhs.phase) return true; - } - else return false; - } - - bool operator>(const qc_height& rhs) { - if (block_height > rhs.block_height) return true; - else if (block_height == rhs.block_height){ - if (phase > rhs.phase) return true; - } - else return false; - } - - };*/ - struct quorum_certificate { public: - block_id_type block_id; + fc::sha256 proposal_id; + + bool quorum_met = false; vector active_finalizers; fc::crypto::blslib::bls_signature active_agg_sig; - std::optional> incoming_finalizers; - std::optional incoming_agg_sig; - - uint32_t block_num()const{ - return compute_block_num(block_id); - } - - /*bool quorum_met(extended_schedule es, bool dual_set_mode){ - - if ( dual_set_mode && - incoming_finalizers.has_value() && - incoming_agg_sig.has_value()){ - return _quorum_met(es, active_finalizers, active_agg_sig) && _quorum_met(es, incoming_finalizers.value(), incoming_agg_sig.value()); - } - else { - return _quorum_met(es, active_finalizers, active_agg_sig); - } - - }; - - private: - bool _quorum_met(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig){ - - ilog("evaluating if _quorum_met"); - - if (finalizers.size() != _threshold){ - - ilog("finalizers.size() ${size}", ("size",finalizers.size())); - return false; - - } - - ilog("correct threshold"); - - fc::crypto::blslib::bls_public_key agg_key; - - for (name f : finalizers) { - - auto itr = es.bls_pub_keys.find(f); - - if (itr==es.bls_pub_keys.end()) return false; - - agg_key = fc::crypto::blslib::aggregate({agg_key, itr->second }); - - } - - std::vector msg = std::vector(block_id.data(), block_id.data() + 32); - - bool ok = fc::crypto::blslib::verify(agg_key, msg, agg_sig); - - return ok; - - return true; //temporary - - }*/ - }; struct hs_vote_message { - block_id_type block_id; //vote on proposal + fc::sha256 proposal_id; //vote on proposal name finalizer; fc::crypto::blslib::bls_signature sig; hs_vote_message() = default; - uint32_t block_num()const{ +/* uint32_t block_num()const{ return compute_block_num(block_id); - } + }*/ }; struct hs_proposal_message { - block_id_type block_id; //new proposal + fc::sha256 proposal_id; //vote on proposal + + block_id_type block_id; + uint8_t phase_counter; - std::optional justify; //justification + fc::sha256 parent_id; //new proposal + + fc::sha256 final_on_qc; + + quorum_certificate justify; //justification hs_proposal_message() = default; - + uint32_t block_num()const{ return compute_block_num(block_id); } + uint64_t get_height()const { + return compute_height(compute_block_num(block_id), phase_counter); + }; + }; struct hs_new_block_message { block_id_type block_id; //new proposal - std::optional justify; //justification + quorum_certificate justify; //justification hs_new_block_message() = default; - - uint32_t block_num()const{ - return compute_block_num(block_id); - } - }; struct hs_new_view_message { - std::optional high_qc; //justification + quorum_certificate high_qc; //justification hs_new_view_message() = default; @@ -193,13 +114,8 @@ namespace eosio { namespace chain { }} //eosio::chain -//FC_REFLECT_ENUM( eosio::chain::consensus_msg_type, -// (cm_new_view)(cm_prepare)(cm_pre_commit)(cm_commit)(cm_decide) ); - -//FC_REFLECT(eosio::chain::consensus_node, (header)(previous_bmroot)(schedule_hash)(digest_to_sign)); -FC_REFLECT(eosio::chain::quorum_certificate, (block_id)(active_finalizers)(active_agg_sig)(incoming_finalizers)(incoming_agg_sig)); -//FC_REFLECT(eosio::chain::proposal, (block)(justify)); -FC_REFLECT(eosio::chain::hs_vote_message, (block_id)(finalizer)(sig)); -FC_REFLECT(eosio::chain::hs_proposal_message, (block_id)(justify)); +FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); +FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); +FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(phase_counter)(parent_id)(final_on_qc)(justify)); FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify)); FC_REFLECT(eosio::chain::hs_new_view_message, (high_qc)); \ No newline at end of file diff --git a/libraries/libfc/test/CMakeLists.txt b/libraries/libfc/test/CMakeLists.txt index 9b6077befe..a904794c39 100644 --- a/libraries/libfc/test/CMakeLists.txt +++ b/libraries/libfc/test/CMakeLists.txt @@ -18,4 +18,8 @@ add_test(NAME test_filesystem COMMAND test_filesystem WORKING_DIRECTORY ${CMAKE_ add_executable( test_bls test_bls.cpp ) target_link_libraries( test_bls fc ) -add_test(NAME test_bls COMMAND libraries/libfc/test/test_bls WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) \ No newline at end of file +add_test(NAME test_bls COMMAND libraries/libfc/test/test_bls WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + +add_executable( test_hotstuff test_hotstuff.cpp ) +target_link_libraries( test_hotstuff fc ) +add_test(NAME test_hotstuff COMMAND libraries/libfc/test/test_hotstuff WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) \ No newline at end of file diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp index 8fbd3c4e95..8b177295cf 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp @@ -7,48 +7,22 @@ namespace eosio { namespace chain { const uint32_t INTERUPT_TIMEOUT = 6; //sufficient timeout for new leader to be selected - class qc_chain { - public: - -/* const string msg_type_to_string(consensus_msg_type t) { - switch (t) { - case cm_new_view: return "cm_new_view"; - case cm_prepare: return "cm_prepare"; - case cm_pre_commit: return "cm_pre_commit"; - case cm_commit: return "cm_commit"; - case cm_decide: return "cm_decide"; - default: return "unknown"; - } - } - - enum qc_chain_state { - initializing = 1, - leading_view = 2, //only leader can lead view - processing_view = 3, - finished_view = 4 - };*/ + class qc_chain { + public: qc_chain( ){}; ~qc_chain(){}; -/* - digest_type get_digest_to_sign(consensus_msg_type msg_type, uint32_t view_number, digest_type digest_to_sign); - - void init(chain_plugin* chain_plug, std::set my_producers); //begins or resume a new qc chain - - void create_new_view(block_state hbs); //begins a new view - void request_new_view(); //request a new view from the leader -*/ name get_proposer(); name get_leader(); name get_incoming_leader(); - bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal, bool dual_set_mode); + bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); std::vector get_finalizers(); - hs_proposal_message new_proposal_candidate(block_state& hbs); - hs_new_block_message new_new_block_candidate(block_state& hbs); + hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); + hs_new_block_message new_block_candidate(block_id_type block_id); void init(chain_plugin& chain_plug, std::set my_producers); @@ -56,7 +30,6 @@ namespace eosio { namespace chain { bool am_i_proposer(); bool am_i_leader(); - bool am_i_incoming_leader(); bool am_i_finalizer(); void process_proposal(hs_proposal_message msg); @@ -69,77 +42,29 @@ namespace eosio { namespace chain { void broadcast_hs_new_view(hs_new_view_message msg); void broadcast_hs_new_block(hs_new_block_message msg); - bool extends(block_id_type descendant, block_id_type ancestor); + bool extends(fc::sha256 descendant, fc::sha256 ancestor); void on_beat(block_state& hbs); void update_high_qc(eosio::chain::quorum_certificate high_qc); - void on_leader_rotate(block_id_type block_id); + void on_leader_rotate(); bool is_node_safe(hs_proposal_message proposal); - - //eosio::chain::quorum_certificate get_updated_quorum(hs_vote_message vote); - - //eosio::chain::quorum_certificate create_or_get_qc(hs_vote_message proposal); - - //void add_to_qc(eosio::chain::quorum_certificate& qc, name finalizer, fc::crypto::blslib::bls_signature sig); + std::vector get_qc_chain(fc::sha256 proposal_id); + void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler void update(hs_proposal_message proposal); - void commit(block_header_state_ptr block); - - std::mutex _proposal_mutex; - std::mutex _vote_mutex; - std::mutex _new_view_mutex; - std::mutex _new_block_mutex; - - - -/* - - void process_confirmation_msg(confirmation_message msg, bool self_confirming); //process confirmation msg - void process_consensus_msg(consensus_message msg, bool self_leading); //process consensus msg - - void emit_confirm(confirmation_message msg); //send confirmation message - void emit_new_phase(consensus_message msg); //send consensus message - - void on_new_view_interrupt(); // - - void commit(block_header header); - - void print_state(); - - std::mutex _confirmation_mutex; - std::mutex _consensus_mutex; - - chain_plugin* _chain_plug = nullptr; - - std::set _my_producers; - - qc_chain_state _qc_chain_state; - - uint32_t _view_number; - chain::account_name _view_leader; - vector _view_finalizers; - - std::optional _prepareQC; - std::optional _lockedQC; - - fc::crypto::blslib::bls_private_key _private_key; - - quorum_certificate _currentQC; - + void commit(hs_proposal_message proposal); - uint32_t _view_liveness_threshold; + void clear_old_data(uint64_t cutoff); - vector _processed_confirmation_msgs; - vector _processed_consensus_msgs; -*/ + std::mutex _hotstuff_state_mutex; - }; + }; }} /// eosio::qc_chain \ No newline at end of file diff --git a/plugins/producer_plugin/qc_chain.cpp b/plugins/producer_plugin/qc_chain.cpp index 00e7f7c821..29290a3fc2 100644 --- a/plugins/producer_plugin/qc_chain.cpp +++ b/plugins/producer_plugin/qc_chain.cpp @@ -10,20 +10,93 @@ #include -//todo list notes : +#include +#include -// add QC to block header +#include + +//todo list / notes : + +/* + + + +fork tests in unittests + + + +network plugin versioning + +handshake_message.network_version + +independant of protocol feature activation + + + +separate library for hotstuff (look at SHIP libray used by state history plugin ) + + +boost tests producer plugin test + + + +regression tests python framework as a base + + + +performance testing + + + + +*/ + + + +// +// complete proposer / leader differentiation +// integration with new bls implementation // -// add optimistically responsive mode +// hotstuff as a library with its own tests (model on state history plugin + state_history library ) +// +// unit / integration tests -> producer_plugin + fork_tests tests as a model +// +// test deterministic sequence +// +// test non-replica participation +// test finality vioaltion +// test loss of liveness +// +// test split chain +// +// integration with fork_db / LIB overhaul +// +// integration with performance testing +// +// regression testing ci/cd -> python regression tests +// +// add APIs for proof data +// +// add election proposal in block header +// +// map proposers / finalizers / leader to new host functions +// +// support pause / resume producer +// +// keep track of proposals sent to peers +// +// allow syncing of proposals +// +// versioning of net protocol version +// +// protocol feature activation HOTSTUFF_CONSENSUS +// +// system contract update 1 -> allow BPs to register + prove their aggregate pub key. Allow existing BPs to unreg + reg without new aggregate key. Prevent new BPs from registering without proving aggregate pub key +// +// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available // -// under optimistically responsive mode, proposal height also includes a phase counter. // -// 0 for proposal (prepare phase) -// 1 for prepareQC (precommit phase) -// 2 for precommitQC (commit phase) -// 3 for commitQC (decide phase)). -// -// The phase counter extends the block height for the monotony check, so that a proposal where block height equals 2,131,059 and is in precommit phase (prepareQC reached) would have a view number of (2131059, 2). If the proposal is accepted and completes the commit phase , the view number becomes (2131059, 3) which respects the monotony rule + namespace eosio { namespace chain { using boost::multi_index_container; @@ -45,72 +118,95 @@ namespace eosio { namespace chain { uint32_t _v_height; + bool _chained_mode = false ; + + void handle_eptr(std::exception_ptr eptr){ + try { + if (eptr) { + std::rethrow_exception(eptr); + } + } catch(const std::exception& e) { + ilog("Caught exception ${ex}" , ("ex", e.what())); + std::exit(0); + } + } const block_id_type NULL_BLOCK_ID = block_id_type("00"); + const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - const block_header_state_ptr NULL_BLOCK_HEADER_STATE_PTR = block_header_state_ptr(); - const block_state_ptr NULL_BLOCK_STATE_PTR = block_state_ptr(); +/* const block_header_state_ptr NULL_BLOCK_HEADER_STATE_PTR = block_header_state_ptr(); + const block_state_ptr NULL_BLOCK_STATE_PTR = block_state_ptr();*/ - block_id_type _b_leaf = NULL_BLOCK_ID; - block_id_type _b_lock = NULL_BLOCK_ID; - block_id_type _b_exec = NULL_BLOCK_ID; + fc::sha256 _b_leaf = NULL_PROPOSAL_ID; + fc::sha256 _b_lock = NULL_PROPOSAL_ID; + fc::sha256 _b_exec = NULL_PROPOSAL_ID; - eosio::chain::quorum_certificate _high_qc; + block_id_type _block_exec = NULL_BLOCK_ID; - uint32_t _dual_set_height = 0; //0 if single-set mode + eosio::chain::quorum_certificate _high_qc; + eosio::chain::quorum_certificate _current_qc; eosio::chain::extended_schedule _schedule; - chain_plugin* _chain_plug = nullptr; + chain_plugin* _chain_plug = nullptr; std::set _my_producers; - struct by_block_id{}; - struct by_block_num{}; + block_id_type _pending_proposal_block = NULL_BLOCK_ID; - typedef multi_index_container< - eosio::chain::quorum_certificate, - indexed_by< - hashed_unique< - tag, - BOOST_MULTI_INDEX_MEMBER(eosio::chain::quorum_certificate,block_id_type,block_id) - >, - ordered_unique< - tag, - BOOST_MULTI_INDEX_CONST_MEM_FUN(eosio::chain::quorum_certificate,uint32_t,block_num) - > - > - > qc_store_type; + struct by_proposal_id{}; + struct by_proposal_height{}; typedef multi_index_container< hs_proposal_message, indexed_by< hashed_unique< - tag, - BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,block_id_type,block_id) + tag, + BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) >, ordered_unique< - tag, - BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint32_t,block_num) + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) > > > proposal_store_type; - qc_store_type _qc_store; proposal_store_type _proposal_store; - digest_type get_digest_to_sign(fc::crypto::blslib::bls_signature agg_sig, block_id_type block_id){ - digest_type h = digest_type::hash( std::make_pair( agg_sig, block_id ) ); + digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ + + digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); + digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); - return h; + return h2; } + std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ + + std::vector ret_arr; + + proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); + + b_2_itr = _proposal_store.get().find( proposal_id ); + if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); + if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); + + if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); + if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); + if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); + + return ret_arr; + + } + name qc_chain::get_proposer(){ chain::controller& chain = _chain_plug->chain(); - const auto& hbs = chain.head_block_state(); + const auto& hbs = chain.head_block_state(); return hbs->header.producer; @@ -120,102 +216,159 @@ namespace eosio { namespace chain { chain::controller& chain = _chain_plug->chain(); - const auto& hbs = chain.head_block_state(); + const auto& hbs = chain.head_block_state(); return hbs->header.producer; } - name qc_chain::get_incoming_leader(){ + + std::vector qc_chain::get_finalizers(){ chain::controller& chain = _chain_plug->chain(); - //verify if leader changed - signed_block_header current_block_header = chain.head_block_state()->header; + const auto& hbs = chain.head_block_state(); - block_timestamp_type next_block_time = current_block_header.timestamp.next(); + return hbs->active_schedule.producers; - producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); + } + + hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { + + hs_proposal_message b_new; - return p_auth.producer_name ; + b_new.block_id = block_id; + b_new.parent_id = _b_leaf; + b_new.phase_counter = phase_counter; - } + b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - std::vector qc_chain::get_finalizers(){ + if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ - chain::controller& chain = _chain_plug->chain(); + std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); - const auto& hbs = chain.head_block_state(); + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - return hbs->active_schedule.producers; + if (chain_length>=2){ + + auto itr = current_qc_chain.begin(); + + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + + if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; + else { + + proposal_store_type::nth_index<0>::type::iterator p_itr; + + p_itr = _proposal_store.get().find( b1.parent_id ); + + b_new.final_on_qc = p_itr->final_on_qc; + + } + + } + + } + + b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); + + ilog("=== creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + ("block_num", b_new.block_num()) + ("phase_counter", b_new.phase_counter) + ("proposal_id", b_new.proposal_id) + ("parent_id", b_new.parent_id) + ("justify", b_new.justify.proposal_id)); + + return b_new; } - hs_proposal_message qc_chain::new_proposal_candidate(block_state& hbs) { - - hs_proposal_message b; + void reset_qc(fc::sha256 proposal_id){ - b.block_id = hbs.header.calculate_id(); - b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + _current_qc.proposal_id = proposal_id; + _current_qc.quorum_met = false; + _current_qc.active_finalizers = {}; + _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); - return b; } - hs_new_block_message qc_chain::new_new_block_candidate(block_state& hbs) { + hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { hs_new_block_message b; - b.block_id = hbs.header.calculate_id(); + b.block_id = block_id; b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch return b; } - bool _quorum_met(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ - + bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ +/* +std::exception_ptr eptr; +try{*/ - if (finalizers.size() != _threshold){ - //ilog("finalizers.size() ${size}", ("size",finalizers.size())); - return false; - } + if (finalizers.size() < _threshold){ + return false; + } - ilog("correct threshold of finalizers. Verifying signatures"); - - fc::crypto::blslib::bls_public_key agg_key; + fc::crypto::blslib::bls_public_key agg_key; - for (int i = 0; i < finalizers.size(); i++) { + for (int i = 0; i < finalizers.size(); i++) { - //adding finalizer's key to the aggregate pub key - if (i==0) agg_key = _private_key.get_public_key(); - else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); + //adding finalizer's key to the aggregate pub key + if (i==0) agg_key = _private_key.get_public_key(); + else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); - } + } - fc::crypto::blslib::bls_signature justification_agg_sig; + fc::crypto::blslib::bls_signature justification_agg_sig; - if (proposal.justify.has_value()) justification_agg_sig = proposal.justify.value().active_agg_sig; + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; - digest_type digest = get_digest_to_sign(justification_agg_sig, proposal.block_id); + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - std::vector h = std::vector(digest.data(), digest.data() + 32); + std::vector h = std::vector(digest.data(), digest.data() + 32); - bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); + bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); - return ok; + return ok; - } +/*} +catch (...){ + ilog("error during evaluate_quorum"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr);*/ - bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal, bool dual_set_mode){ + } - if ( dual_set_mode && - qc.incoming_finalizers.has_value() && - qc.incoming_agg_sig.has_value()){ - return _quorum_met(schedule, qc.active_finalizers, qc.active_agg_sig, proposal) && _quorum_met(schedule, qc.incoming_finalizers.value(), qc.incoming_agg_sig.value(), proposal); - } - else { - return _quorum_met(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); - } + bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ + +/*std::exception_ptr eptr; +try{ +*/ + if (qc.quorum_met == true ) { + return true; //skip evaluation if we've already verified quorum was met + } + else { + + //ilog("qc : ${qc}", ("qc", qc)); + bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); + + qc.quorum_met = quorum_met; + + return qc.quorum_met ; + + } +/*} +catch (...){ + ilog("error during find proposals"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr);*/ } void qc_chain::init(chain_plugin& chain_plug, std::set my_producers){ @@ -223,7 +376,7 @@ namespace eosio { namespace chain { _chain_plug = &chain_plug; _my_producers = my_producers; - ilog("qc chain initialized -> my producers : "); + //ilog("qc chain initialized -> my producers : "); } @@ -250,19 +403,6 @@ namespace eosio { namespace chain { else return true; } - - bool qc_chain::am_i_incoming_leader(){ - - name leader = get_incoming_leader(); - - //ilog("Incoming leader : ${leader}", ("leader", leader)); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); - - if (prod_itr==_my_producers.end()) return false; - else return true; - - } bool qc_chain::am_i_leader(){ @@ -299,94 +439,50 @@ namespace eosio { namespace chain { } - void qc_chain::process_proposal(hs_proposal_message msg){ - - //todo : block candidate validation hook (check if block is valid, etc.), return if not - - /* - - First, we verify if we have already are aware of the proposal, and if the QC was updated - - */ + void qc_chain::process_proposal(hs_proposal_message proposal){ - ilog("=== Process proposal #${block_num} ${block_id}", ("block_id", msg.block_id)("block_num", msg.block_num())); - bool skip_sign = false; + auto itr = _proposal_store.get().find( proposal.proposal_id ); - auto itr = _proposal_store.get().find( msg.block_num() ); - - //if we already received a proposal at this block height - if (itr != _proposal_store.get().end()){ - - //we check if it is the same proposal we already received. If it is, it is a duplicate message and we don't have anything else to do. If it isn't, it may indicate double signing - //todo : store conflicting proposals for accountability purposes - if (itr->block_id != msg.block_id){ - - ilog("conflicting proposal at block height : ${block_num} ", ("block_num", msg.block_num())); - - } - - skip_sign = true; //duplicate - - } - else { + if (itr != _proposal_store.get().end()) { + ilog("*** proposal received twice : ${proposal_id}",("proposal_id", proposal.proposal_id)); + return ; //already aware of proposal, nothing to do - ilog("new proposal. Adding to storage"); - - _proposal_store.insert(msg); //new block proposal - } - //check if I'm finalizer + ilog("=== received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id) + ("parent_id", proposal.parent_id) + ("justify", proposal.justify.proposal_id)); - //ilog("updating state"); - - //update internal state - update(msg); - - //ilog("checking if I should sign proposal"); + _proposal_store.insert(proposal); //new proposal bool am_finalizer = am_i_finalizer(); - bool node_safe = is_node_safe(msg); - - //ilog("am_finalizer : ${am_finalizer}", ("am_finalizer", am_finalizer)); - //ilog("node_safe : ${node_safe}", ("node_safe", node_safe)); - - bool signature_required = !skip_sign && am_finalizer && node_safe; + bool node_safe = is_node_safe(proposal); + bool signature_required = am_finalizer && node_safe; //if I am a finalizer for this proposal, test safenode predicate for possible vote if (signature_required){ //ilog("signature required"); - _v_height = msg.block_num(); - - /* - Sign message. - - In Hotstuff, we need to sign a tuple of (msg.view_type, msg.view_number and msg.node). - - In our implementation, the view_type is generic, and the view_number and message node are both contained in the block_id. - - Therefore, we can ensure uniqueness by replacing the view_type with msg.block_candidate.justify.agg_sig. - - The digest to sign now becomes the tuple (msg.block_candidate.justify.agg_sig, msg.block_candidate.block_id). - - */ + _v_height = proposal.get_height(); fc::crypto::blslib::bls_signature agg_sig; - if (msg.justify.has_value()) agg_sig = msg.justify.value().active_agg_sig; + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; - digest_type digest = get_digest_to_sign(agg_sig, msg.block_id); + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); std::vector h = std::vector(digest.data(), digest.data() + 32); //iterate over all my finalizers and sign / broadcast for each that is in the schedule std::vector finalizers = get_finalizers(); - ilog("signed proposal. Broadcasting for each of my producers"); + //ilog("signed proposal. Broadcasting for each of my producers"); auto mf_itr = _my_producers.begin(); @@ -398,7 +494,7 @@ namespace eosio { namespace chain { fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer - hs_vote_message v_msg = {msg.block_id, prod_itr->producer_name, sig}; + hs_vote_message v_msg = {proposal.proposal_id, prod_itr->producer_name, sig}; broadcast_hs_vote(v_msg); @@ -408,15 +504,17 @@ namespace eosio { namespace chain { } - //check for leader change - on_leader_rotate(msg.block_id); - } + //update internal state + update(proposal); + //check for leader change + on_leader_rotate(); + } - void qc_chain::process_vote(hs_vote_message msg){ + void qc_chain::process_vote(hs_vote_message vote){ //check for duplicate or invalid vote, return in either case //abstracted [...] @@ -425,71 +523,76 @@ namespace eosio { namespace chain { if(!am_leader) return; - ilog("=== Process vote from ${finalizer}", ("finalizer", msg.finalizer)); - - eosio::chain::quorum_certificate qc; + //ilog("=== Process vote from ${finalizer}", ("finalizer", vote.finalizer)); //only leader need to take action on votes - qc_store_type::nth_index<0>::type::iterator itr = _qc_store.get().find( msg.block_id ); + if (vote.proposal_id != _current_qc.proposal_id) return; - if (itr!=_qc_store.get().end()){ + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( msg.block_id ); + if (p_itr==_proposal_store.get().end()){ + ilog("*** couldn't find proposal"); - if (p_itr==_proposal_store.get().end()){ - ilog("couldn't find proposal"); - } + ilog("*** vote : ${vote}", ("vote", vote)); - bool quorum_met = is_quorum_met(*itr, _schedule, *p_itr, false); + return; + } - if (!quorum_met){ - - _qc_store.modify( itr, [&]( auto& qc ) { - qc.active_finalizers.push_back(msg.finalizer); - qc.active_agg_sig = fc::crypto::blslib::aggregate({qc.active_agg_sig, msg.sig }); - }); + bool quorum_met = _current_qc.quorum_met; //check if quorum already met + + if (!quorum_met){ - quorum_met = is_quorum_met(*itr, _schedule, *p_itr, false); + _current_qc.active_finalizers.push_back(vote.finalizer); - if (quorum_met){ + if (_current_qc.active_finalizers.size()>1) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); + else _current_qc.active_agg_sig = vote.sig; - ilog("=== Quorum met on #${block_num} : ${block_id}", ("block_num", compute_block_num(msg.block_id))("block_id", msg.block_id)); + quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); - update_high_qc(*itr); + if (quorum_met){ - chain::controller& chain = _chain_plug->chain(); + _current_qc.quorum_met = true; + + //ilog("=== Quorum met on #${block_num} ${proposal_id} ", ("block_num", p_itr->block_num())("proposal_id", vote.proposal_id)); + + ilog("=== update_high_qc : _current_qc ==="); + update_high_qc(_current_qc); + + //check for leader change + on_leader_rotate(); - //todo : optimistically-responsive liveness progress - - } - - } - - } - else { - ilog(" must create new qc for proposal"); + //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet + if (_chained_mode==false && p_itr->phase_counter<3){ - //new QC is created + hs_proposal_message proposal_candidate; - qc.block_id = msg.block_id; - qc.active_finalizers.push_back(msg.finalizer); - qc.active_agg_sig = msg.sig; + if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); + else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); + + reset_qc(proposal_candidate.proposal_id); - _qc_store.insert(qc); + _pending_proposal_block = NULL_BLOCK_ID; + broadcast_hs_proposal(proposal_candidate); + + _b_leaf = proposal_candidate.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + + } + + } + } } - void qc_chain::process_new_view(hs_new_view_message msg){ + void qc_chain::process_new_view(hs_new_view_message new_view){ - ilog("=== Process new view ==="); - - bool am_leader = am_i_leader(); //am I leader? - - if(!am_leader) return; + ilog("=== update_high_qc : process_new_view === ${qc}", ("qc", new_view.high_qc)); + update_high_qc(new_view.high_qc); } @@ -557,42 +660,51 @@ namespace eosio { namespace chain { } //extends predicate - bool qc_chain::extends(block_id_type descendant, block_id_type ancestor){ + bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ + //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified - block_header_state_ptr itr = get_block_header(descendant); - //block_header_state_ptr a_itr = get_block_header(ancestor); -/* if (a_itr == NULL_BLOCK_HEADER_STATE_PTR){ - ilog("ancestor does't exist, returning true"); - return true; - }*/ + proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); + + uint32_t counter = 0; - while (itr!=NULL_BLOCK_HEADER_STATE_PTR){ + while (itr!=_proposal_store.get().end()){ - itr = get_block_header(itr->header.previous); + itr = _proposal_store.get().find(itr->parent_id ); - if (itr->id == ancestor) return true; + if (itr->proposal_id == ancestor){ + if (counter>25) { + ilog("***"); + ilog("*** took ${counter} iterations to find ancestor ", ("counter", counter)); + ilog("***"); + + } + return true; + } + counter++; } - ilog(" ***** extends returned false : could not find #${d_block_num} ${d_block_id} descending from #${a_block_num} ${a_block_id} ", - ("d_block_num", compute_block_num(descendant)) - ("d_block_id", descendant) - ("a_block_num", compute_block_num(ancestor)) - ("a_block_id", ancestor)); + ilog(" ***** extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", + ("d_proposal_id", descendant) + ("a_proposal_id", ancestor)); return false; } - + void qc_chain::on_beat(block_state& hbs){ +std::exception_ptr eptr; +try{ + + std::lock_guard g( this-> _hotstuff_state_mutex ); ilog("=== on beat ==="); - if (hbs.header.producer == "eosio"_n) return ; + if (hbs.header.producer == "eosio"_n) return ; //if chain has not been activated and doesn't have finalizers, we don't generate proposals bool am_proposer = am_i_proposer(); bool am_leader = am_i_leader(); @@ -615,47 +727,104 @@ namespace eosio { namespace chain { //todo : extra validation } + - hs_proposal_message block_candidate = new_proposal_candidate(hbs); - - _b_leaf = block_candidate.block_id; + if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ + + _pending_proposal_block = hbs.header.calculate_id(); + + } + else { + + hs_proposal_message proposal_candidate = new_proposal_candidate(hbs.header.calculate_id(), 0 ); + + reset_qc(proposal_candidate.proposal_id); - ilog("=== broadcasting proposal = #${block_num} ${block_id}", ("block_id", block_candidate.block_id)("block_num", block_candidate.block_num())); + _pending_proposal_block = NULL_BLOCK_ID; + + broadcast_hs_proposal(proposal_candidate); - broadcast_hs_proposal(block_candidate); + _b_leaf = proposal_candidate.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + + } } else { //if I'm only a proposer and not the leader, I send a new block message - hs_new_block_message block_candidate = new_new_block_candidate(hbs); + hs_new_block_message block_candidate = new_block_candidate(hbs.header.calculate_id()); - ilog("=== broadcasting new block = #${block_num} ${block_id}", ("block_id", block_candidate.block_id)("block_num", block_candidate.block_num())); + //ilog("=== broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); broadcast_hs_new_block(block_candidate); } - + //ilog(" === end of on_beat"); +} +catch (...){ + ilog("error during on_beat"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); } void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ + + ilog("=== check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); + // if new high QC is higher than current, update to new - if (high_qc.block_num()>_high_qc.block_num()){ + - ilog("=== updating high qc, now is : #${block_num} ${block_id}", ("block_num", compute_block_num(high_qc.block_id))("block_id", high_qc.block_id)); + if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ _high_qc = high_qc; - _b_leaf = _high_qc.block_id; + _b_leaf = _high_qc.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + + } + else { + + proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; + proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; + + old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); + new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); + + if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); + if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); + - } + if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ + + bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); + + if (quorum_met){ + + high_qc.quorum_met = true; + + //ilog("=== updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); + + _high_qc = high_qc; + _b_leaf = _high_qc.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + + } + + } + + } } - void qc_chain::on_leader_rotate(block_id_type block_id){ + void qc_chain::on_leader_rotate(){ - //ilog("on_leader_rotate"); + ilog("on_leader_rotate"); chain::controller& chain = _chain_plug->chain(); @@ -664,18 +833,22 @@ namespace eosio { namespace chain { block_timestamp_type next_block_time = current_block_header.timestamp.next(); - ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", - ("old_timestamp", current_block_header.timestamp)("new_timestamp", current_block_header.timestamp.next())); + //ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", + // ("old_timestamp", current_block_header.timestamp)("new_timestamp", current_block_header.timestamp.next())); producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); if (current_block_header.producer != p_auth.producer_name){ - ilog("=== rotating leader : ${old_leader} -> ${new_leader} ", + ilog("/// rotating leader : ${old_leader} -> ${new_leader} ", ("old_leader", current_block_header.producer)("new_leader", p_auth.producer_name)); //leader changed, we send our new_view message + reset_qc(NULL_PROPOSAL_ID); + + _pending_proposal_block = NULL_BLOCK_ID; + hs_new_view_message new_view; new_view.high_qc = _high_qc; @@ -694,683 +867,350 @@ namespace eosio { namespace chain { bool monotony_check = false; bool safety_check = false; bool liveness_check = false; + bool final_on_qc_check = false; + + fc::sha256 upcoming_commit; + + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated + else { + + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + if (chain_length>=2){ + + auto itr = current_qc_chain.begin(); + + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + + if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; + else { + + proposal_store_type::nth_index<0>::type::iterator p_itr; + + p_itr = _proposal_store.get().find( b1.parent_id ); + + upcoming_commit = p_itr->final_on_qc; + + } + + } + + //abstracted [...] + if (upcoming_commit == proposal.final_on_qc){ + final_on_qc_check = true; + } + + } - if (proposal.block_num() > _v_height){ + if (proposal.get_height() > _v_height){ monotony_check = true; } - if (_b_lock != NULL_BLOCK_ID){ + if (_b_lock != NULL_PROPOSAL_ID){ //Safety check : check if this proposal extends the chain I'm locked on - if (extends(proposal.block_id, _b_lock)){ + if (extends(proposal.proposal_id, _b_lock)){ safety_check = true; } //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. - if (!proposal.justify.has_value()) liveness_check = true; - else if (proposal.justify.value().block_num() > compute_block_num(_b_lock)){ - liveness_check = true; + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated + else { + + proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); + proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); + + if (prop_justification->get_height() > b_lock->get_height()){ + liveness_check = true; + } } } else { + ilog("not locked on anything, liveness and safety are true"); + //if we're not locked on anything, means the protocol just activated or chain just launched liveness_check = true; safety_check = true; } - ilog("=== safety check : monotony : ${monotony_check}, liveness : ${liveness_check}, safety : ${safety_check}", +/* ilog("=== final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", + ("final_on_qc_check", final_on_qc_check) ("monotony_check", monotony_check) ("liveness_check", liveness_check) - ("safety_check", safety_check)); + ("safety_check", safety_check));*/ - return monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully + return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully } //on proposal received, called from network thread void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ +std::exception_ptr eptr; +try{ //ilog("=== on_hs_proposal_msg ==="); - std::lock_guard g( this->_proposal_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_proposal_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block process_proposal(msg); + //ilog(" === end of on_hs_proposal_msg"); +} +catch (...){ + ilog("error during on_hs_proposal_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); } //on vote received, called from network thread void qc_chain::on_hs_vote_msg(hs_vote_message msg){ - +std::exception_ptr eptr; +try{ + //ilog("=== on_hs_vote_msg ==="); - std::lock_guard g( this->_vote_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_vote_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block process_vote(msg); - + + //ilog(" === end of on_hs_vote_msg"); + } +catch (...){ + ilog("error during on_hs_vote_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); } //on new view received, called from network thread void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ +std::exception_ptr eptr; +try{ //ilog("=== on_hs_new_view_msg ==="); - std::lock_guard g( this->_new_view_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_new_view_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block process_new_view(msg); + //ilog(" === end of on_hs_new_view_msg"); +} +catch (...){ + ilog("error during on_hs_new_view_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); } //on new block received, called from network thread void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ - +std::exception_ptr eptr; +try{ + //ilog("=== on_hs_new_block_msg ==="); - std::lock_guard g( this->_new_block_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_new_block_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block process_new_block(msg); + //ilog(" === end of on_hs_new_block_msg"); +} +catch (...){ + ilog("error during on_hs_new_block_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); } void qc_chain::update(hs_proposal_message proposal){ - - ilog("=== update internal state ==="); + //ilog("=== update internal state ==="); chain::controller& chain = _chain_plug->chain(); - //proposal_store_type::nth_index<0>::type::iterator b_new_itr = _proposal_store.get().find( proposal.block_id ); //guaranteed to exist - - //should all be guaranteed to exist ? - proposal_store_type::nth_index<0>::type::iterator b_2_itr; - proposal_store_type::nth_index<0>::type::iterator b_1_itr; - proposal_store_type::nth_index<0>::type::iterator b_itr; - - b_2_itr = _proposal_store.get().find( proposal.justify.value().block_id ); - b_1_itr = _proposal_store.get().find( b_2_itr->justify.value().block_id ); - b_itr = _proposal_store.get().find( b_1_itr->justify.value().block_id ); - - block_header_state_ptr b_2_header = get_block_header(b_2_itr->block_id); - block_header_state_ptr b_1_header = get_block_header(b_1_itr->block_id); - block_header_state_ptr b_header = get_block_header(b_itr->block_id); - - ilog("b_2_itr->block_id : #${block_num}: ${block_id}" ,("block_num", compute_block_num(b_2_itr->block_id))("block_id", b_2_itr->block_id)); - ilog("b_1_itr->block_id : #${block_num}:${block_id}" ,("block_num", compute_block_num(b_1_itr->block_id))("block_id", b_1_itr->block_id)); - ilog("b_itr->block_id : #${block_num}:${block_id}" ,("block_num", compute_block_num(b_itr->block_id))("block_id", b_itr->block_id)); - - //todo : check if pending transition of finalizer set exists - - - if (b_2_itr==_proposal_store.get().end()) return; - //ilog("proposal.justify exists"); - - update_high_qc(proposal.justify.value()); - - if (b_1_itr==_proposal_store.get().end()) return; - //ilog("b_2_itr->justify exists"); - - if (compute_block_num(b_1_itr->block_id) > compute_block_num(_b_lock)){ - ilog("commit phase on block : #${block_num}:${block_id}" ,("block_num", compute_block_num(b_1_itr->block_id))("block_id", b_1_itr->block_id)); - _b_lock = b_1_itr->block_id; //commit phase on b1 - //ilog("lock confirmed"); - } - - if (b_itr==_proposal_store.get().end()) return; - //ilog("b_1_itr->justify exists"); - - ilog("parent relationship verification : b_2->previous ${b_2_previous} b_1->block_id ${b_1_block_id} b_1->previous ${b_1_previous} b->block_id ${b_block_id}", - ("b_2_previous", b_2_header->header.previous)("b_1_block_id", b_1_itr->block_id)("b_1_previous",b_1_header->header.previous)("b_block_id",b_itr->block_id)); - - //direct parent relationship verification - if (b_2_header->header.previous == b_1_itr->block_id && b_1_header->header.previous == b_itr->block_id){ - - ilog("direct parent relationship verified"); - - //if we are currently operating in dual set mode reaching this point, and the block we are about to commit has a height higher or equal to me._dual_set_height, it means we have reached extended quorum on a view ready to be committed, so we can transition into single_set mode again, where the incoming finalizer set becomes the active finalizer set - if (_dual_set_height != 0 && compute_block_num(b_itr->block_id) >= _dual_set_height){ - - ilog("transitionning out of dual set mode"); - - //sanity check to verify quorum on justification for b (b1), should always evaluate to true - //if (b_itr->justify.extended_quorum_met()){ - - //reset internal state to single_set mode, with new finalizer set - //me._schedule.block_finalizers = me_.schedule.incoming_finalizers; - //me_.schedule.incoming_finalizers = null; - //me._dual_set_height = -1; - - //} - - } - - commit(b_header); - - ilog("last executed block : #${block_num} ${block_id}", ("block_num", compute_block_num(b_itr->block_id))("block_id", b_itr->block_id)); - - _b_exec = b_itr->block_id; //decide phase on b - - ilog("completed commit"); + proposal_store_type::nth_index<0>::type::iterator b_lock; + //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ + ilog("*** proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)); + return; } - else { - - ilog("could not verify direct parent relationship"); - } + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - //ilog("=== end update ==="); + b_lock = _proposal_store.get().find( _b_lock); - } + ilog("=== update_high_qc : proposal.justify ==="); + update_high_qc(proposal.justify); - void qc_chain::commit(block_header_state_ptr block){ - - block_header_state_ptr b_exec = get_block_header(_b_exec); - - bool sequence_respected; - - if (b_exec == NULL_BLOCK_HEADER_STATE_PTR) { - ilog("first block committed"); - sequence_respected = true; - + if (chain_length<1){ + ilog("*** qc chain length is 0"); + return; } - else sequence_respected = b_exec->header.block_num() < block->header.block_num(); - if (sequence_respected){ - - block_header_state_ptr p_itr = get_block_header(block->header.previous); - - if (p_itr != NULL_BLOCK_HEADER_STATE_PTR){ - - ilog("=== recursively committing" ); - - commit(p_itr); //recursively commit all non-committed ancestor blocks sequentially first - - } - - //execute block cmd - //abstracted [...] - - ilog("=== committed block #${block_id}", ("block_id", block->header.block_num())); + auto itr = current_qc_chain.begin(); + hs_proposal_message b_2 = *itr; + if (chain_length<2){ + ilog("*** qc chain length is 1"); + return; } - } - -/* - digest_type qc_chain::get_digest_to_sign(consensus_msg_type msg_type, uint32_t view_number, digest_type digest_to_sign){ - - string s_cmt = msg_type_to_string(msg_type); - string s_view_number = to_string(view_number); - - string s_c = s_cmt + s_view_number; - - digest_type h1 = digest_type::hash(s_c); - digest_type h2 = digest_type::hash( std::make_pair( h1, digest_to_sign ) ); - - return h2; - - } - - void qc_chain::init(chain_plugin* chain_plug, std::set my_producers){ - - std::vector seed_1 = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, - 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, - 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; - - ilog("init qc chain"); - - _qc_chain_state = initializing; - _my_producers = my_producers; - - _chain_plug = chain_plug; - - _private_key = fc::crypto::blslib::bls_private_key(seed_1); - - } - - //create a new view based on the block we just produced - void qc_chain::create_new_view(block_state hbs){ - - _view_number++; - _view_leader = hbs.header.producer; - _view_finalizers = hbs.active_schedule.producers; - - _qc_chain_state = leading_view; - - digest_type previous_bmroot = hbs.blockroot_merkle.get_root(); - digest_type schedule_hash = hbs.pending_schedule.schedule_hash; - - digest_type header_bmroot = digest_type::hash(std::make_pair(hbs.header.digest(), previous_bmroot)); - digest_type digest_to_sign = digest_type::hash(std::make_pair(header_bmroot, schedule_hash)); - - consensus_node cn = {hbs.header, previous_bmroot, schedule_hash, digest_to_sign}; - - std::optional qc; - - if (_prepareQC.has_value()) qc = _prepareQC.value(); - else qc = std::nullopt; - - consensus_message msg = {cm_prepare, _view_number, cn, qc} ; - - ilog("creating new view #${view_number} : leader : ${view_leader}", - ("view_number", _view_number)("view_leader", _view_leader)); - - vector finalizers; - - _currentQC = {msg.msg_type, msg.view_number, msg.node, finalizers, fc::crypto::blslib::bls_signature("")};; - - emit_new_phase(msg); - - - } - - void qc_chain::request_new_view(){ - - //ilog("request new view"); - - _view_number++; - - _qc_chain_state = processing_view; - - //consensus_node cn = _prepareQC.node; - //consensus_message msg = {cm_new_view, _view_number, cn, std::nullopt}; - - //emit_new_phase(msg); - - } - -*/ - -/* - - void qc_chain::process_confirmation_msg(confirmation_message msg, bool self_confirming){ - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == _view_leader; }); - - if (prod_itr==_my_producers.end()) return; //if we're not producing, we can ignore any confirmation messages - - auto itr = std::find_if(_processed_confirmation_msgs.begin(), _processed_confirmation_msgs.end(), [ &msg](confirmation_message m){ - return m.msg_type == msg.msg_type && - m.view_number == msg.view_number && - m.node.digest_to_sign == msg.node.digest_to_sign && - m.finalizer == msg.finalizer; - }); - - if (itr!=_processed_confirmation_msgs.end()) { - //ilog("WRONG already processed this message"); - return; //already processed - } - else{ - //ilog("new confirmation message. Processing..."); - _processed_confirmation_msgs.push_back(msg); - - if (_processed_confirmation_msgs.size()==100) _processed_confirmation_msgs.erase(_processed_confirmation_msgs.begin()); - - } - - if (_currentQC.msg_type == msg.msg_type && //check if confirmation message is for that QC - _currentQC.view_number == msg.view_number){ - - if (std::find(_currentQC.finalizers.begin(), _currentQC.finalizers.end(), msg.finalizer) == _currentQC.finalizers.end()){ - - //ilog("new finalizer vote received for this QC"); - - //verify signature - fc::crypto::blslib::bls_public_key pk = _private_key.get_public_key(); - - digest_type digest = get_digest_to_sign(msg.msg_type, msg.view_number, msg.node.digest_to_sign ); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - bool ok = verify(pk, h, msg.sig); - - if (ok==false){ - //ilog("WRONG signature invalid"); - return; - } - - fc::crypto::blslib::bls_signature n_sig; - - if (_currentQC.finalizers.size() == 0) n_sig = msg.sig; - else n_sig = fc::crypto::blslib::aggregate({_currentQC.sig,msg.sig}); - - - _currentQC.sig = n_sig; - _currentQC.finalizers.push_back(msg.finalizer); + itr++; - if (_currentQC.finalizers.size()==14){ + hs_proposal_message b_1 = *itr; - ilog("reached quorum on ${msg_type}, can proceed with next phase", - ("msg_type", msg.msg_type)); + //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock + if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ - //received enough confirmations to move to next phase - consensus_msg_type next_phase; + //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); + _b_lock = b_1.proposal_id; //commit phase on b1 - switch (_currentQC.msg_type) { - case cm_prepare: - next_phase = cm_pre_commit; - _prepareQC = _currentQC; - break; - case cm_pre_commit: - next_phase = cm_commit; - break; - case cm_commit: - next_phase = cm_decide; - break; - } - - consensus_message n_msg = {next_phase, _currentQC.view_number, _currentQC.node, _currentQC}; - - vector finalizers; - - quorum_certificate qc = {next_phase, _currentQC.view_number, _currentQC.node, finalizers, fc::crypto::blslib::bls_signature("")}; - - _currentQC = qc; - - emit_new_phase(n_msg); - - //ilog("sent next phase message"); - - if (next_phase==cm_decide){ - - uint32_t block_height = n_msg.node.header.block_num(); - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - uint32_t distance_from_head = hbs->header.block_num() - block_height; - - ilog("decide decision has been reached on view #${view_number}. Block #${block_height} can be commited safely. Distance from head : ${distance_from_head}", - ("view_number", msg.view_number) - ("block_height", block_height) - ("distance_from_head", distance_from_head)); - - _qc_chain_state=finished_view; - - //if we're still producing, we can start a new view - if (std::find(_my_producers.begin(), _my_producers.end(), hbs->header.producer) != _my_producers.end()){ - create_new_view(*hbs); - } - - } - - } - else { - //uint32_t remaining = 14 - _currentQC.finalizers.size(); - - //ilog("need ${remaining} more votes to move to next phase", ("remaining", remaining)); - } - - } - else { - //ilog("WRONG already received vote for finalizer on this QC "); - - - } + ilog("=== _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)); } - else { - //confirmation applies to another message - //ilog("WRONG QC"); + if (chain_length<3){ + ilog("*** qc chain length is 2"); + return; } - } - - void qc_chain::process_consensus_msg(consensus_message msg, bool self_leading){ - - - auto itr = std::find_if(_processed_consensus_msgs.begin(), _processed_consensus_msgs.end(), [ &msg](consensus_message m){ - return m.msg_type == msg.msg_type && - m.view_number == msg.view_number && - m.node.digest_to_sign == msg.node.digest_to_sign; - }); - - if (itr!=_processed_consensus_msgs.end()){ - //ilog("WRONG already processed this message"); - return; //already processed - } - else { - //ilog("new consensus message. Processing..."); - _processed_consensus_msgs.push_back(msg); - - if (_processed_consensus_msgs.size()==100) _processed_consensus_msgs.erase(_processed_consensus_msgs.begin()); - - } - - //TODO validate message - - digest_type digest = get_digest_to_sign(msg.msg_type, msg.view_number, msg.node.digest_to_sign ); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - //if we're leading the view, reject the consensus message - //if (_qc_chain_state==leading_view) return; - - if (msg.justify.has_value()) { - - auto justify = msg.justify.value(); + itr++; - if (justify.finalizers.size() == 14){ - - fc::crypto::blslib::bls_public_key agg_pk = _private_key.get_public_key(); - - //verify QC - for (size_t i = 1 ; i < justify.finalizers.size();i++){ - agg_pk = fc::crypto::blslib::aggregate({agg_pk,_private_key.get_public_key()}); - } - - digest_type digest_j = get_digest_to_sign(justify.msg_type, justify.view_number, justify.node.digest_to_sign ); - std::vector hj = std::vector(digest_j.data(), digest_j.data() + 32); - - bool ok = verify(agg_pk, hj, justify.sig); - - if (ok==false){ - //ilog("WRONG aggregate signature invalid"); - return; - } + hs_proposal_message b = *itr; - _view_number = msg.view_number; +/* ilog("direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", + ("b_2.parent_id",b_2.parent_id) + ("b_1.proposal_id", b_1.proposal_id) + ("b_1.parent_id", b_1.parent_id) + ("b.proposal_id", b.proposal_id));*/ - if (justify.msg_type == cm_pre_commit){ - _prepareQC = justify; - } - else if (justify.msg_type == cm_pre_commit){ - _lockedQC = justify; - } - } - else { - - //ilog("WRONG invalid consensus message justify argument"); - - return ; - } - } - - if (_qc_chain_state==initializing || _qc_chain_state==finished_view ) { - _view_number = msg.view_number; - _view_leader = msg.node.header.producer; - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - _view_finalizers = hbs->active_schedule.producers; - - _qc_chain_state=processing_view; - - } - - //if we received a commit decision and we are not also leading this round - if (msg.msg_type == cm_decide && self_leading == false){ + //direct parent relationship verification + if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ - uint32_t block_height = msg.node.header.block_num(); + //ilog("direct parent relationship verified"); - chain::controller& chain = _chain_plug->chain(); - const auto& hbs = chain.head_block_state(); + commit(b); - uint32_t distance_from_head = hbs->header.block_num() - block_height; + //ilog("last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); - ilog("decide decision has been reached on view #${view_number}. Block #${block_height} can be commited safely. Distance from head : ${distance_from_head}", - ("view_number", msg.view_number) - ("block_height", block_height) - ("distance_from_head", distance_from_head)); + //ilog("setting _b_exec to ${proposal_id}", ("proposal_id",b.proposal_id )); + _b_exec = b.proposal_id; //decide phase on b + _block_exec = b.block_id; - //if current producer is not previous view leader, we must send a new_view message with our latest prepareQC - if (hbs->header.producer != _view_leader){ - //_view_number++; - _view_leader = hbs->header.producer; - _qc_chain_state=finished_view; - } + clear_old_data( b.get_height()-1); //todo : figure out what number is actually needed - return; + //ilog("completed commit"); } else { - auto p_itr = _my_producers.begin(); - - while(p_itr!= _my_producers.end()){ - - chain::account_name finalizer = *p_itr; - - auto itr = std::find_if(_view_finalizers.begin(), _view_finalizers.end(), [&](const auto& asp){ return asp.producer_name == finalizer; }); - - if (itr!= _view_finalizers.end()){ - - //ilog("Signing confirmation..."); - - fc::crypto::blslib::bls_signature sig = _private_key.sign(h);; + ilog("*** could not verify direct parent relationship"); - confirmation_message n_msg = {msg.msg_type, msg.view_number, msg.node, finalizer, sig}; + ilog("*** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); + ilog("*** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); + ilog("*** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); - //ilog("Sending confirmation message for ${finalizer}", ("finalizer", finalizer)); - - emit_confirm(n_msg); - - } - else { - //finalizer not in view schedule - //ilog("WRONG consensus ${finalizer}", ("finalizer", finalizer)); - - } - - p_itr++; - } - } - } - void qc_chain::emit_confirm(confirmation_message msg){ - chain::controller& chain = _chain_plug->chain(); + } - confirmation_message_ptr ptr = std::make_shared(msg); + void qc_chain::clear_old_data(uint64_t cutoff){ - chain.commit_confirmation_msg(ptr); + //std::lock_guard g1( this->_proposal_store_mutex ); + //std::lock_guard g2( this-> _qc_store_mutex ); - process_confirmation_msg(msg, true); //notify ourselves, in case we are also the view leader + //ilog("clearing old data"); - } + auto end_itr = _proposal_store.get().upper_bound(cutoff); - void qc_chain::emit_new_phase(consensus_message msg){ - - chain::controller& chain = _chain_plug->chain(); - - ilog("emit new phase ${msg_type}... view #${view_number} on block #${block_num}", - ("msg_type",msg.msg_type) - ("view_number",msg.view_number) - ("block_num",msg.node.header.block_num()) ); + while (_proposal_store.get().begin() != end_itr){ - consensus_message_ptr ptr = std::make_shared(msg); + auto itr = _proposal_store.get().begin(); - chain.commit_consensus_msg(ptr); + ilog("erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + ("block_num", itr->block_num()) + ("phase_counter", itr->phase_counter) + ("block_id", itr->block_id) + ("proposal_id", itr->proposal_id)); - process_consensus_msg(msg, true); //notify ourselves, in case we are also running finalizers + //auto qc_itr = _qc_store.get().find(itr->proposal_id); - } + //if (qc_itr!=_qc_store.get().end()) _qc_store.get().erase(qc_itr); + _proposal_store.get().erase(itr); - void qc_chain::on_new_view_interrupt(){ - - } - void qc_chain::commit(block_header header){ + } } - void qc_chain::print_state(){ + void qc_chain::commit(hs_proposal_message proposal){ - ilog("QC CHAIN STATE : "); - - ilog(" view number : ${view_number}, view leader : ${view_leader}", - ("view_number", _view_number) - ("view_leader", _view_leader)); - - - if (_prepareQC.has_value()){ - - quorum_certificate prepareQC = _prepareQC.value(); - - ilog(" prepareQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", - ("msg_type", prepareQC.msg_type) - ("view_number", prepareQC.view_number) - ("block_num", prepareQC.node.header.block_num())); - - ilog(" finalizers : "); - - for (int i = 0 ; i < prepareQC.finalizers.size(); i++){ - ilog(" ${finalizer}", - ("finalizer", prepareQC.finalizers[i])); - } +/* ilog("=== attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", proposal.block_num()) + ("proposal_id", proposal.proposal_id) + ("block_id", proposal.block_id) + ("phase_counter", proposal.phase_counter) + ("parent_id", proposal.parent_id)); + */ + bool sequence_respected = false; + proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); + +/* ilog("=== _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", last_exec_prop->block_num()) + ("proposal_id", last_exec_prop->proposal_id) + ("block_id", last_exec_prop->block_id) + ("phase_counter", last_exec_prop->phase_counter) + ("parent_id", last_exec_prop->parent_id));*/ + + if (_b_exec==NULL_PROPOSAL_ID){ + //ilog("first block committed"); + sequence_respected = true; } - else { - ilog(" no prepareQC"); - } + else sequence_respected = last_exec_prop->get_height() < proposal.get_height(); + if (sequence_respected){ + + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); - if (_lockedQC.has_value()){ + if (p_itr != _proposal_store.get().end()){ - quorum_certificate lockedQC = _lockedQC.value(); + //ilog("=== recursively committing" ); - ilog(" lockedQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", - ("msg_type", lockedQC.msg_type) - ("view_number", lockedQC.view_number) - ("block_num", lockedQC.node.header.block_num())); + commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first - ilog(" finalizers : "); - - for (int i = 0 ; i < lockedQC.finalizers.size(); i++){ - ilog(" ${finalizer}", - ("finalizer", lockedQC.finalizers[i])); } - } - else { - ilog(" no _lockedQC"); - } - - ilog(" _currentQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", - ("msg_type", _currentQC.msg_type) - ("view_number", _currentQC.view_number) - ("block_num", _currentQC.node.header.block_num())); - - ilog(" finalizers : "); + ilog("=== committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("block_id", proposal.block_id) + ("proposal_id", proposal.proposal_id)); - for (int i = 0 ; i < _currentQC.finalizers.size(); i++){ - ilog(" ${finalizer}", - ("finalizer", _currentQC.finalizers[i])); } - ilog(" _processed_confirmation_msgs count : ${count}", - ("count", _processed_confirmation_msgs.size())); - - ilog(" _processed_consensus_msgs count : ${count}", - ("count", _processed_consensus_msgs.size())); - - } -*/ + }} From 0deeba7b8c2e493130f2ed5771cc1193802740d6 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Thu, 9 Mar 2023 14:36:25 +0000 Subject: [PATCH 010/151] Re-engineered hotstuff as a library --- libraries/CMakeLists.txt | 1 + libraries/libfc/test/CMakeLists.txt | 4 -- plugins/producer_plugin/CMakeLists.txt | 3 +- .../eosio/producer_plugin/producer_plugin.hpp | 2 +- .../eosio/producer_plugin/qc_chain.hpp | 70 ------------------- plugins/producer_plugin/producer_plugin.cpp | 5 +- plugins/producer_plugin/qc_chain.cpp | 2 +- 7 files changed, 7 insertions(+), 80 deletions(-) delete mode 100644 plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp diff --git a/libraries/CMakeLists.txt b/libraries/CMakeLists.txt index 44909fcb7c..0c23ecd8cf 100644 --- a/libraries/CMakeLists.txt +++ b/libraries/CMakeLists.txt @@ -16,6 +16,7 @@ add_subdirectory( testing ) add_subdirectory( version ) add_subdirectory( state_history ) add_subdirectory( cli11 ) +add_subdirectory( hotstuff ) set(USE_EXISTING_SOFTFLOAT ON CACHE BOOL "use pre-exisiting softfloat lib") set(ENABLE_TOOLS OFF CACHE BOOL "Build tools") diff --git a/libraries/libfc/test/CMakeLists.txt b/libraries/libfc/test/CMakeLists.txt index a904794c39..29963c83da 100644 --- a/libraries/libfc/test/CMakeLists.txt +++ b/libraries/libfc/test/CMakeLists.txt @@ -19,7 +19,3 @@ add_test(NAME test_filesystem COMMAND test_filesystem WORKING_DIRECTORY ${CMAKE_ add_executable( test_bls test_bls.cpp ) target_link_libraries( test_bls fc ) add_test(NAME test_bls COMMAND libraries/libfc/test/test_bls WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) - -add_executable( test_hotstuff test_hotstuff.cpp ) -target_link_libraries( test_hotstuff fc ) -add_test(NAME test_hotstuff COMMAND libraries/libfc/test/test_hotstuff WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) \ No newline at end of file diff --git a/plugins/producer_plugin/CMakeLists.txt b/plugins/producer_plugin/CMakeLists.txt index 159cd69291..6f9a2fbf2f 100644 --- a/plugins/producer_plugin/CMakeLists.txt +++ b/plugins/producer_plugin/CMakeLists.txt @@ -2,12 +2,11 @@ file(GLOB HEADERS "include/eosio/producer_plugin/*.hpp") add_library( producer_plugin producer_plugin.cpp - qc_chain.cpp pending_snapshot.cpp ${HEADERS} ) -target_link_libraries( producer_plugin chain_plugin http_client_plugin signature_provider_plugin appbase eosio_chain ) +target_link_libraries( producer_plugin chain_plugin http_client_plugin signature_provider_plugin appbase eosio_chain hotstuff) target_include_directories( producer_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../chain_interface/include" ) diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index 0656c87f68..21f14aa794 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp deleted file mode 100644 index 8b177295cf..0000000000 --- a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once -#include -#include -#include - -namespace eosio { namespace chain { - - const uint32_t INTERUPT_TIMEOUT = 6; //sufficient timeout for new leader to be selected - - class qc_chain { - public: - - qc_chain( ){}; - ~qc_chain(){}; - - name get_proposer(); - name get_leader(); - name get_incoming_leader(); - - bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); - - std::vector get_finalizers(); - - hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); - hs_new_block_message new_block_candidate(block_id_type block_id); - - void init(chain_plugin& chain_plug, std::set my_producers); - - block_header_state_ptr get_block_header( const block_id_type& id ); - - bool am_i_proposer(); - bool am_i_leader(); - bool am_i_finalizer(); - - void process_proposal(hs_proposal_message msg); - void process_vote(hs_vote_message msg); - void process_new_view(hs_new_view_message msg); - void process_new_block(hs_new_block_message msg); - - void broadcast_hs_proposal(hs_proposal_message msg); - void broadcast_hs_vote(hs_vote_message msg); - void broadcast_hs_new_view(hs_new_view_message msg); - void broadcast_hs_new_block(hs_new_block_message msg); - - bool extends(fc::sha256 descendant, fc::sha256 ancestor); - - void on_beat(block_state& hbs); - - void update_high_qc(eosio::chain::quorum_certificate high_qc); - - void on_leader_rotate(); - - bool is_node_safe(hs_proposal_message proposal); - - std::vector get_qc_chain(fc::sha256 proposal_id); - - void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler - void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler - void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler - - void update(hs_proposal_message proposal); - void commit(hs_proposal_message proposal); - - void clear_old_data(uint64_t cutoff); - - std::mutex _hotstuff_state_mutex; - - }; -}} /// eosio::qc_chain \ No newline at end of file diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 4a8a547832..4fc49614ba 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -350,7 +350,7 @@ class producer_plugin_impl : public std::enable_shared_from_this _accepted_block_header_connection; std::optional _irreversible_block_connection; - qc_chain _qc_chain; + eosio::hotstuff::qc_chain _qc_chain; /* * HACK ALERT @@ -1015,7 +1015,8 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ } } - my->_qc_chain.init(*my->chain_plug, my->_producers); + + my->_qc_chain.init(&chain, my->_producers); } FC_LOG_AND_RETHROW() } diff --git a/plugins/producer_plugin/qc_chain.cpp b/plugins/producer_plugin/qc_chain.cpp index 29290a3fc2..093174fc82 100644 --- a/plugins/producer_plugin/qc_chain.cpp +++ b/plugins/producer_plugin/qc_chain.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include From 35c1cff2dba5872fdad4412c2b686b292fca9658 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Thu, 16 Mar 2023 19:49:19 +0000 Subject: [PATCH 011/151] Refactor for easier unit testing --- .../chain/include/eosio/chain/hotstuff.hpp | 6 +- .../eosio/producer_plugin/producer_plugin.hpp | 1 + plugins/producer_plugin/producer_plugin.cpp | 15 +- plugins/producer_plugin/qc_chain.cpp | 1216 ----------------- 4 files changed, 13 insertions(+), 1225 deletions(-) delete mode 100644 plugins/producer_plugin/qc_chain.cpp diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 6098649751..c1df5eb302 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -13,10 +13,10 @@ namespace eosio { namespace chain { //todo : fetch from chain / nodeos config - const uint32_t block_interval = 500; - const uint32_t blocks_per_round = 12; +/* const uint32_t block_interval = 500; + const uint32_t blocks_per_round = 12;*/ - const uint32_t _threshold = 15; + static uint32_t compute_block_num(block_id_type block_id) { diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index 21f14aa794..8b693acb71 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 4fc49614ba..af45b6f2b0 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -352,6 +352,8 @@ class producer_plugin_impl : public std::enable_shared_from_this_chain_pacemaker.init(&chain); - my->_qc_chain.init(&chain, my->_producers); + my->_qc_chain.init("main"_n, my->_chain_pacemaker, my->_producers); } FC_LOG_AND_RETHROW() } @@ -2520,19 +2523,19 @@ static auto maybe_make_debug_time_logger() -> std::optional -#include - -#include -#include -#include -#include -#include -#include -#include - - -#include -#include - -#include - -//todo list / notes : - -/* - - - -fork tests in unittests - - - -network plugin versioning - -handshake_message.network_version - -independant of protocol feature activation - - - -separate library for hotstuff (look at SHIP libray used by state history plugin ) - - -boost tests producer plugin test - - - -regression tests python framework as a base - - - -performance testing - - - - -*/ - - - -// -// complete proposer / leader differentiation -// integration with new bls implementation -// -// hotstuff as a library with its own tests (model on state history plugin + state_history library ) -// -// unit / integration tests -> producer_plugin + fork_tests tests as a model -// -// test deterministic sequence -// -// test non-replica participation -// test finality vioaltion -// test loss of liveness -// -// test split chain -// -// integration with fork_db / LIB overhaul -// -// integration with performance testing -// -// regression testing ci/cd -> python regression tests -// -// add APIs for proof data -// -// add election proposal in block header -// -// map proposers / finalizers / leader to new host functions -// -// support pause / resume producer -// -// keep track of proposals sent to peers -// -// allow syncing of proposals -// -// versioning of net protocol version -// -// protocol feature activation HOTSTUFF_CONSENSUS -// -// system contract update 1 -> allow BPs to register + prove their aggregate pub key. Allow existing BPs to unreg + reg without new aggregate key. Prevent new BPs from registering without proving aggregate pub key -// -// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available -// -// - - -namespace eosio { namespace chain { - using boost::multi_index_container; - using namespace boost::multi_index; - - //todo : remove. bls12-381 key used for testing purposes - std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, - 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, - 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; - - fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); - - enum msg_type { - new_view = 1, - new_block = 2, - qc = 3, - vote = 4 - }; - - uint32_t _v_height; - - bool _chained_mode = false ; - - void handle_eptr(std::exception_ptr eptr){ - try { - if (eptr) { - std::rethrow_exception(eptr); - } - } catch(const std::exception& e) { - ilog("Caught exception ${ex}" , ("ex", e.what())); - std::exit(0); - } - } - - const block_id_type NULL_BLOCK_ID = block_id_type("00"); - const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - -/* const block_header_state_ptr NULL_BLOCK_HEADER_STATE_PTR = block_header_state_ptr(); - const block_state_ptr NULL_BLOCK_STATE_PTR = block_state_ptr();*/ - - fc::sha256 _b_leaf = NULL_PROPOSAL_ID; - fc::sha256 _b_lock = NULL_PROPOSAL_ID; - fc::sha256 _b_exec = NULL_PROPOSAL_ID; - - block_id_type _block_exec = NULL_BLOCK_ID; - - eosio::chain::quorum_certificate _high_qc; - eosio::chain::quorum_certificate _current_qc; - - eosio::chain::extended_schedule _schedule; - - chain_plugin* _chain_plug = nullptr; - std::set _my_producers; - - block_id_type _pending_proposal_block = NULL_BLOCK_ID; - - struct by_proposal_id{}; - struct by_proposal_height{}; - - typedef multi_index_container< - hs_proposal_message, - indexed_by< - hashed_unique< - tag, - BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) - >, - ordered_unique< - tag, - BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) - > - > - > proposal_store_type; - - proposal_store_type _proposal_store; - - - digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ - - digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); - digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); - - return h2; - - } - - std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ - - std::vector ret_arr; - - proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); - - b_2_itr = _proposal_store.get().find( proposal_id ); - if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); - if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); - - if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); - if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); - if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); - - return ret_arr; - - } - - name qc_chain::get_proposer(){ - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - return hbs->header.producer; - - } - - name qc_chain::get_leader(){ - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - return hbs->header.producer; - - } - - - std::vector qc_chain::get_finalizers(){ - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - return hbs->active_schedule.producers; - - } - - hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { - - hs_proposal_message b_new; - - b_new.block_id = block_id; - b_new.parent_id = _b_leaf; - b_new.phase_counter = phase_counter; - - b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - - if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ - - std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - if (chain_length>=2){ - - auto itr = current_qc_chain.begin(); - - hs_proposal_message b2 = *itr; - itr++; - hs_proposal_message b1 = *itr; - - if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; - else { - - proposal_store_type::nth_index<0>::type::iterator p_itr; - - p_itr = _proposal_store.get().find( b1.parent_id ); - - b_new.final_on_qc = p_itr->final_on_qc; - - } - - } - - } - - b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); - - ilog("=== creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", - ("block_num", b_new.block_num()) - ("phase_counter", b_new.phase_counter) - ("proposal_id", b_new.proposal_id) - ("parent_id", b_new.parent_id) - ("justify", b_new.justify.proposal_id)); - - return b_new; - - } - - void reset_qc(fc::sha256 proposal_id){ - - _current_qc.proposal_id = proposal_id; - _current_qc.quorum_met = false; - _current_qc.active_finalizers = {}; - _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); - - } - - hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { - - hs_new_block_message b; - - b.block_id = block_id; - b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - - return b; - } - - bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ -/* -std::exception_ptr eptr; -try{*/ - - if (finalizers.size() < _threshold){ - return false; - } - - fc::crypto::blslib::bls_public_key agg_key; - - for (int i = 0; i < finalizers.size(); i++) { - - //adding finalizer's key to the aggregate pub key - if (i==0) agg_key = _private_key.get_public_key(); - else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); - - } - - fc::crypto::blslib::bls_signature justification_agg_sig; - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; - - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); - - return ok; - -/*} -catch (...){ - ilog("error during evaluate_quorum"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr);*/ - - } - - bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ - -/*std::exception_ptr eptr; -try{ -*/ - if (qc.quorum_met == true ) { - return true; //skip evaluation if we've already verified quorum was met - } - else { - - //ilog("qc : ${qc}", ("qc", qc)); - - bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); - - qc.quorum_met = quorum_met; - - return qc.quorum_met ; - - } -/*} -catch (...){ - ilog("error during find proposals"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr);*/ - } - - void qc_chain::init(chain_plugin& chain_plug, std::set my_producers){ - - _chain_plug = &chain_plug; - _my_producers = my_producers; - - //ilog("qc chain initialized -> my producers : "); - - - } - - block_header_state_ptr qc_chain::get_block_header( const block_id_type& id ){ - - //ilog("get_block_header "); - - chain::controller& chain = _chain_plug->chain(); - - return chain.fork_db().get_block_header(id); - - } - - bool qc_chain::am_i_proposer(){ - - name proposer = get_proposer(); - - //ilog("Proposer : ${proposer}", ("proposer", proposer)); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); - - if (prod_itr==_my_producers.end()) return false; - else return true; - - } - - bool qc_chain::am_i_leader(){ - - name leader = get_leader(); - - //ilog("Leader : ${leader}", ("leader", leader)); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); - - if (prod_itr==_my_producers.end()) return false; - else return true; - - } - - bool qc_chain::am_i_finalizer(){ - - //ilog("am_i_finalizer"); - - std::vector finalizers = get_finalizers(); - - auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); - - if (prod_itr!=finalizers.end()) return true; - - mf_itr++; - - } - - return false; - - } - - void qc_chain::process_proposal(hs_proposal_message proposal){ - - - auto itr = _proposal_store.get().find( proposal.proposal_id ); - - if (itr != _proposal_store.get().end()) { - ilog("*** proposal received twice : ${proposal_id}",("proposal_id", proposal.proposal_id)); - return ; //already aware of proposal, nothing to do - - } - - ilog("=== received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id) - ("parent_id", proposal.parent_id) - ("justify", proposal.justify.proposal_id)); - - _proposal_store.insert(proposal); //new proposal - - bool am_finalizer = am_i_finalizer(); - bool node_safe = is_node_safe(proposal); - - bool signature_required = am_finalizer && node_safe; - - //if I am a finalizer for this proposal, test safenode predicate for possible vote - if (signature_required){ - - //ilog("signature required"); - - _v_height = proposal.get_height(); - - fc::crypto::blslib::bls_signature agg_sig; - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; - - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - //iterate over all my finalizers and sign / broadcast for each that is in the schedule - std::vector finalizers = get_finalizers(); - - //ilog("signed proposal. Broadcasting for each of my producers"); - - auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); - - if (prod_itr!=finalizers.end()) { - - fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer - - hs_vote_message v_msg = {proposal.proposal_id, prod_itr->producer_name, sig}; - - broadcast_hs_vote(v_msg); - - }; - - mf_itr++; - - } - - } - - //update internal state - update(proposal); - - //check for leader change - on_leader_rotate(); - - } - - void qc_chain::process_vote(hs_vote_message vote){ - - //check for duplicate or invalid vote, return in either case - //abstracted [...] - - bool am_leader = am_i_leader(); //am I leader? - - if(!am_leader) return; - - //ilog("=== Process vote from ${finalizer}", ("finalizer", vote.finalizer)); - - //only leader need to take action on votes - - if (vote.proposal_id != _current_qc.proposal_id) return; - - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); - - if (p_itr==_proposal_store.get().end()){ - ilog("*** couldn't find proposal"); - - ilog("*** vote : ${vote}", ("vote", vote)); - - return; - } - - bool quorum_met = _current_qc.quorum_met; //check if quorum already met - - if (!quorum_met){ - - _current_qc.active_finalizers.push_back(vote.finalizer); - - if (_current_qc.active_finalizers.size()>1) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); - else _current_qc.active_agg_sig = vote.sig; - - quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); - - if (quorum_met){ - - _current_qc.quorum_met = true; - - //ilog("=== Quorum met on #${block_num} ${proposal_id} ", ("block_num", p_itr->block_num())("proposal_id", vote.proposal_id)); - - ilog("=== update_high_qc : _current_qc ==="); - update_high_qc(_current_qc); - - //check for leader change - on_leader_rotate(); - - - //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet - if (_chained_mode==false && p_itr->phase_counter<3){ - - hs_proposal_message proposal_candidate; - - if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); - else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); - - reset_qc(proposal_candidate.proposal_id); - - _pending_proposal_block = NULL_BLOCK_ID; - - broadcast_hs_proposal(proposal_candidate); - - _b_leaf = proposal_candidate.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); - - } - - } - - } - - } - - void qc_chain::process_new_view(hs_new_view_message new_view){ - - ilog("=== update_high_qc : process_new_view === ${qc}", ("qc", new_view.high_qc)); - update_high_qc(new_view.high_qc); - - } - - void qc_chain::process_new_block(hs_new_block_message msg){ - - //ilog("=== Process new block ==="); - - } - - void qc_chain::broadcast_hs_proposal(hs_proposal_message msg){ - - //ilog("=== broadcast_hs_proposal ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_proposal_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_proposal_msg(ptr); - - process_proposal(msg); - - } - - - void qc_chain::broadcast_hs_vote(hs_vote_message msg){ - - //ilog("=== broadcast_hs_vote ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_vote_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_vote_msg(ptr); - - process_vote(msg); - - } - - void qc_chain::broadcast_hs_new_view(hs_new_view_message msg){ - - //ilog("=== broadcast_hs_new_view ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_new_view_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_new_view_msg(ptr); - - //process_new_view(msg); //notify ourselves - - } - - void qc_chain::broadcast_hs_new_block(hs_new_block_message msg){ - - //ilog("=== broadcast_hs_new_block ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_new_block_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_new_block_msg(ptr); - - //process_new_block(msg); //notify ourselves - - } - - //extends predicate - bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ - - - //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified - - - proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); - - uint32_t counter = 0; - - while (itr!=_proposal_store.get().end()){ - - itr = _proposal_store.get().find(itr->parent_id ); - - if (itr->proposal_id == ancestor){ - if (counter>25) { - ilog("***"); - ilog("*** took ${counter} iterations to find ancestor ", ("counter", counter)); - ilog("***"); - - } - return true; - } - - counter++; - - } - - ilog(" ***** extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", - ("d_proposal_id", descendant) - ("a_proposal_id", ancestor)); - - return false; - - } - - void qc_chain::on_beat(block_state& hbs){ -std::exception_ptr eptr; -try{ - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - ilog("=== on beat ==="); - - if (hbs.header.producer == "eosio"_n) return ; //if chain has not been activated and doesn't have finalizers, we don't generate proposals - - bool am_proposer = am_i_proposer(); - bool am_leader = am_i_leader(); - - //ilog("=== am_proposer = ${am_proposer}", ("am_proposer", am_proposer)); - //ilog("=== am_leader = ${am_leader}", ("am_leader", am_leader)); - - if (!am_proposer && !am_leader){ - - return; //nothing to do - - } - - //if I am the leader - if (am_leader){ - - //if I'm not also the proposer, perform block validation as required - if (!am_proposer){ - - //todo : extra validation - - } - - - if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ - - _pending_proposal_block = hbs.header.calculate_id(); - - } - else { - - hs_proposal_message proposal_candidate = new_proposal_candidate(hbs.header.calculate_id(), 0 ); - - reset_qc(proposal_candidate.proposal_id); - - _pending_proposal_block = NULL_BLOCK_ID; - - broadcast_hs_proposal(proposal_candidate); - - _b_leaf = proposal_candidate.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); - - } - - } - else { - - //if I'm only a proposer and not the leader, I send a new block message - - hs_new_block_message block_candidate = new_block_candidate(hbs.header.calculate_id()); - - //ilog("=== broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); - - broadcast_hs_new_block(block_candidate); - - } - - //ilog(" === end of on_beat"); -} -catch (...){ - ilog("error during on_beat"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ - - ilog("=== check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); - - // if new high QC is higher than current, update to new - - - if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ - - _high_qc = high_qc; - _b_leaf = _high_qc.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); - - } - else { - - proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; - proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; - - old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); - new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); - - if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); - if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); - - - if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ - - bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); - - if (quorum_met){ - - high_qc.quorum_met = true; - - //ilog("=== updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); - - _high_qc = high_qc; - _b_leaf = _high_qc.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); - - } - - } - - } - - } - - void qc_chain::on_leader_rotate(){ - - ilog("on_leader_rotate"); - - chain::controller& chain = _chain_plug->chain(); - - //verify if leader changed - signed_block_header current_block_header = chain.head_block_state()->header; - - block_timestamp_type next_block_time = current_block_header.timestamp.next(); - - //ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", - // ("old_timestamp", current_block_header.timestamp)("new_timestamp", current_block_header.timestamp.next())); - - producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); - - if (current_block_header.producer != p_auth.producer_name){ - - ilog("/// rotating leader : ${old_leader} -> ${new_leader} ", - ("old_leader", current_block_header.producer)("new_leader", p_auth.producer_name)); - - //leader changed, we send our new_view message - - reset_qc(NULL_PROPOSAL_ID); - - _pending_proposal_block = NULL_BLOCK_ID; - - hs_new_view_message new_view; - - new_view.high_qc = _high_qc; - - broadcast_hs_new_view(new_view); - } - - - } - - //safenode predicate - bool qc_chain::is_node_safe(hs_proposal_message proposal){ - - //ilog("=== is_node_safe ==="); - - bool monotony_check = false; - bool safety_check = false; - bool liveness_check = false; - bool final_on_qc_check = false; - - fc::sha256 upcoming_commit; - - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated - else { - - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - if (chain_length>=2){ - - auto itr = current_qc_chain.begin(); - - hs_proposal_message b2 = *itr; - itr++; - hs_proposal_message b1 = *itr; - - if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; - else { - - proposal_store_type::nth_index<0>::type::iterator p_itr; - - p_itr = _proposal_store.get().find( b1.parent_id ); - - upcoming_commit = p_itr->final_on_qc; - - } - - } - - //abstracted [...] - if (upcoming_commit == proposal.final_on_qc){ - final_on_qc_check = true; - } - - } - - if (proposal.get_height() > _v_height){ - monotony_check = true; - } - - if (_b_lock != NULL_PROPOSAL_ID){ - - //Safety check : check if this proposal extends the chain I'm locked on - if (extends(proposal.proposal_id, _b_lock)){ - safety_check = true; - } - - //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated - else { - - proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); - proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); - - if (prop_justification->get_height() > b_lock->get_height()){ - liveness_check = true; - } - } - - } - else { - - ilog("not locked on anything, liveness and safety are true"); - - //if we're not locked on anything, means the protocol just activated or chain just launched - liveness_check = true; - safety_check = true; - } - -/* ilog("=== final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", - ("final_on_qc_check", final_on_qc_check) - ("monotony_check", monotony_check) - ("liveness_check", liveness_check) - ("safety_check", safety_check));*/ - - return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully - - } - - //on proposal received, called from network thread - void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_proposal_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_proposal_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_proposal(msg); - - //ilog(" === end of on_hs_proposal_msg"); -} -catch (...){ - ilog("error during on_hs_proposal_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on vote received, called from network thread - void qc_chain::on_hs_vote_msg(hs_vote_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_vote_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_vote_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_vote(msg); - - //ilog(" === end of on_hs_vote_msg"); - } -catch (...){ - ilog("error during on_hs_vote_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on new view received, called from network thread - void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_new_view_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_new_view_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_new_view(msg); - - //ilog(" === end of on_hs_new_view_msg"); -} -catch (...){ - ilog("error during on_hs_new_view_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on new block received, called from network thread - void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_new_block_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_new_block_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_new_block(msg); - - //ilog(" === end of on_hs_new_block_msg"); -} -catch (...){ - ilog("error during on_hs_new_block_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - void qc_chain::update(hs_proposal_message proposal){ - - //ilog("=== update internal state ==="); - - chain::controller& chain = _chain_plug->chain(); - - proposal_store_type::nth_index<0>::type::iterator b_lock; - - //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ - ilog("*** proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)); - return; - } - - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - b_lock = _proposal_store.get().find( _b_lock); - - ilog("=== update_high_qc : proposal.justify ==="); - update_high_qc(proposal.justify); - - if (chain_length<1){ - ilog("*** qc chain length is 0"); - return; - } - - auto itr = current_qc_chain.begin(); - hs_proposal_message b_2 = *itr; - - if (chain_length<2){ - ilog("*** qc chain length is 1"); - return; - } - - itr++; - - hs_proposal_message b_1 = *itr; - - //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock - if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ - - //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); - _b_lock = b_1.proposal_id; //commit phase on b1 - - ilog("=== _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)); - - } - - if (chain_length<3){ - ilog("*** qc chain length is 2"); - return; - } - - itr++; - - hs_proposal_message b = *itr; - -/* ilog("direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", - ("b_2.parent_id",b_2.parent_id) - ("b_1.proposal_id", b_1.proposal_id) - ("b_1.parent_id", b_1.parent_id) - ("b.proposal_id", b.proposal_id));*/ - - //direct parent relationship verification - if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ - - //ilog("direct parent relationship verified"); - - - commit(b); - - //ilog("last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); - - //ilog("setting _b_exec to ${proposal_id}", ("proposal_id",b.proposal_id )); - _b_exec = b.proposal_id; //decide phase on b - _block_exec = b.block_id; - - clear_old_data( b.get_height()-1); //todo : figure out what number is actually needed - - //ilog("completed commit"); - - } - else { - - ilog("*** could not verify direct parent relationship"); - - ilog("*** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); - ilog("*** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); - ilog("*** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); - - } - - - } - - void qc_chain::clear_old_data(uint64_t cutoff){ - - //std::lock_guard g1( this->_proposal_store_mutex ); - //std::lock_guard g2( this-> _qc_store_mutex ); - - //ilog("clearing old data"); - - auto end_itr = _proposal_store.get().upper_bound(cutoff); - - while (_proposal_store.get().begin() != end_itr){ - - auto itr = _proposal_store.get().begin(); - - ilog("erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", - ("block_num", itr->block_num()) - ("phase_counter", itr->phase_counter) - ("block_id", itr->block_id) - ("proposal_id", itr->proposal_id)); - - //auto qc_itr = _qc_store.get().find(itr->proposal_id); - - //if (qc_itr!=_qc_store.get().end()) _qc_store.get().erase(qc_itr); - _proposal_store.get().erase(itr); - - - } - - } - - void qc_chain::commit(hs_proposal_message proposal){ - -/* ilog("=== attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", proposal.block_num()) - ("proposal_id", proposal.proposal_id) - ("block_id", proposal.block_id) - ("phase_counter", proposal.phase_counter) - ("parent_id", proposal.parent_id)); - */ - bool sequence_respected = false; - - proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); - -/* ilog("=== _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", last_exec_prop->block_num()) - ("proposal_id", last_exec_prop->proposal_id) - ("block_id", last_exec_prop->block_id) - ("phase_counter", last_exec_prop->phase_counter) - ("parent_id", last_exec_prop->parent_id));*/ - - if (_b_exec==NULL_PROPOSAL_ID){ - //ilog("first block committed"); - sequence_respected = true; - } - else sequence_respected = last_exec_prop->get_height() < proposal.get_height(); - - if (sequence_respected){ - - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); - - if (p_itr != _proposal_store.get().end()){ - - //ilog("=== recursively committing" ); - - commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first - - } - - ilog("=== committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("block_id", proposal.block_id) - ("proposal_id", proposal.proposal_id)); - - } - - } - -}} - - From 176ac1e96c7faabd67df9334fa09b55c64fffa54 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Thu, 16 Mar 2023 19:49:24 +0000 Subject: [PATCH 012/151] Refactor for easier unit testing --- libraries/hotstuff/CMakeLists.txt | 18 + libraries/hotstuff/chain_pacemaker.cpp | 145 ++ .../include/eosio/hotstuff/base_pacemaker.hpp | 69 + .../eosio/hotstuff/chain_pacemaker.hpp | 56 + .../include/eosio/hotstuff/qc_chain.hpp | 176 +++ .../include/eosio/hotstuff/test_pacemaker.hpp | 123 ++ libraries/hotstuff/qc_chain.cpp | 1073 +++++++++++++++ libraries/hotstuff/test/CMakeLists.txt | 4 + .../test/Testing/Temporary/CTestCostData.txt | 1 + .../test/Testing/Temporary/LastTest.log | 3 + libraries/hotstuff/test/test_hotstuff.cpp | 166 +++ libraries/hotstuff/test_pacemaker.cpp | 303 ++++ libraries/libfc/test/test_hotstuff.cpp.old | 106 ++ .../eosio/producer_plugin/qc_chain.hpp.bkp | 70 + plugins/producer_plugin/qc_chain.cpp.bkp | 1216 +++++++++++++++++ plugins/producer_plugin/qc_chain.old2.cpp | 1216 +++++++++++++++++ tests/hotstuff_tests.cpp | 0 17 files changed, 4745 insertions(+) create mode 100644 libraries/hotstuff/CMakeLists.txt create mode 100644 libraries/hotstuff/chain_pacemaker.cpp create mode 100644 libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp create mode 100644 libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp create mode 100644 libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp create mode 100644 libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp create mode 100644 libraries/hotstuff/qc_chain.cpp create mode 100644 libraries/hotstuff/test/CMakeLists.txt create mode 100644 libraries/hotstuff/test/Testing/Temporary/CTestCostData.txt create mode 100644 libraries/hotstuff/test/Testing/Temporary/LastTest.log create mode 100644 libraries/hotstuff/test/test_hotstuff.cpp create mode 100644 libraries/hotstuff/test_pacemaker.cpp create mode 100644 libraries/libfc/test/test_hotstuff.cpp.old create mode 100644 plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp.bkp create mode 100644 plugins/producer_plugin/qc_chain.cpp.bkp create mode 100644 plugins/producer_plugin/qc_chain.old2.cpp create mode 100644 tests/hotstuff_tests.cpp diff --git a/libraries/hotstuff/CMakeLists.txt b/libraries/hotstuff/CMakeLists.txt new file mode 100644 index 0000000000..b241f56440 --- /dev/null +++ b/libraries/hotstuff/CMakeLists.txt @@ -0,0 +1,18 @@ +file(GLOB HEADERS "include/eosio/hotstuff/*.hpp") + +add_library( hotstuff + test_pacemaker.cpp + chain_pacemaker.cpp + qc_chain.cpp + ${HEADERS} + ) + +target_link_libraries( hotstuff + PUBLIC eosio_chain fc + ) + +target_include_directories( hotstuff + PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" + ) + +add_subdirectory( test ) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp new file mode 100644 index 0000000000..5ac85561aa --- /dev/null +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -0,0 +1,145 @@ +#include +#include + +namespace eosio { namespace hotstuff { + + + void chain_pacemaker::init(controller* chain){ + _chain = chain; + } + + name chain_pacemaker::get_proposer(){ + + const block_state_ptr& hbs = _chain->head_block_state(); + + return hbs->header.producer; + + }; + + name chain_pacemaker::get_leader(){ + + const block_state_ptr& hbs = _chain->head_block_state(); + + return hbs->header.producer; + + }; + + name chain_pacemaker::get_next_leader(){ + + const block_state_ptr& hbs = _chain->head_block_state(); + + block_timestamp_type next_block_time = hbs->header.timestamp.next(); + + producer_authority p_auth = hbs->get_scheduled_producer(next_block_time); + + return p_auth.producer_name; + + }; + + std::vector chain_pacemaker::get_finalizers(){ + + const block_state_ptr& hbs = _chain->head_block_state(); + + std::vector pa_list = hbs->active_schedule.producers; + + std::vector pn_list; + std::transform(pa_list.begin(), pa_list.end(), + std::back_inserter(pn_list), + [](const producer_authority& p) { return p.producer_name; }); + + return pn_list; + + }; + + block_id_type chain_pacemaker::get_current_block_id(){ + + block_header header = _chain->head_block_state()->header; + + block_id_type block_id = header.calculate_id(); + + return block_id; + + } + + uint32_t chain_pacemaker::get_quorum_threshold(){ + return _quorum_threshold; + }; + + void chain_pacemaker::beat(){ + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + _qc_chain->on_beat(); + + }; + + void chain_pacemaker::register_listener(name name, qc_chain& qcc){ + _qc_chain = &qcc; + + }; + + void chain_pacemaker::unregister_listener(name name){ + //delete _qc_chain; + }; + + void chain_pacemaker::send_hs_proposal_msg(hs_proposal_message msg){ + + hs_proposal_message_ptr msg_ptr = std::make_shared(msg); + + _chain->commit_hs_proposal_msg(msg_ptr); + + }; + + void chain_pacemaker::send_hs_vote_msg(hs_vote_message msg){ + + hs_vote_message_ptr msg_ptr = std::make_shared(msg); + + _chain->commit_hs_vote_msg(msg_ptr); + + }; + + void chain_pacemaker::send_hs_new_block_msg(hs_new_block_message msg){ + + hs_new_block_message_ptr msg_ptr = std::make_shared(msg); + + _chain->commit_hs_new_block_msg(msg_ptr); + + }; + + void chain_pacemaker::send_hs_new_view_msg(hs_new_view_message msg){ + + hs_new_view_message_ptr msg_ptr = std::make_shared(msg); + + _chain->commit_hs_new_view_msg(msg_ptr); + + }; + + void chain_pacemaker::on_hs_proposal_msg(hs_proposal_message msg){ + + std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + _qc_chain->on_hs_proposal_msg(msg); + } + + void chain_pacemaker::on_hs_vote_msg(hs_vote_message msg){ + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + _qc_chain->on_hs_vote_msg(msg); + } + + void chain_pacemaker::on_hs_new_block_msg(hs_new_block_message msg){ + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + _qc_chain->on_hs_new_block_msg(msg); + } + + void chain_pacemaker::on_hs_new_view_msg(hs_new_view_message msg){ + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + _qc_chain->on_hs_new_view_msg(msg); + } + +}} \ No newline at end of file diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp new file mode 100644 index 0000000000..7dc2029d0d --- /dev/null +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include +//#include +#include +#include +#include + +using namespace eosio::chain; + +namespace eosio { namespace hotstuff { + + class qc_chain; + + class base_pacemaker{ + + public: + + + //configuration setting + virtual uint32_t get_quorum_threshold() = 0; + + + //polling calls + virtual name get_proposer() = 0; + virtual name get_leader() = 0; + virtual name get_next_leader() = 0; + virtual std::vector get_finalizers() = 0; + + virtual block_id_type get_current_block_id() = 0; + + + + + + + + + + + + //qc_chain event subscription + virtual void register_listener(name name, qc_chain& qcc) = 0; + virtual void unregister_listener(name name) = 0; + + + + + //block / proposal API + virtual void beat() = 0; + + + + + //outbound communications + virtual void send_hs_proposal_msg(hs_proposal_message msg) = 0; + virtual void send_hs_vote_msg(hs_vote_message msg) = 0; + virtual void send_hs_new_block_msg(hs_new_block_message msg) = 0; + virtual void send_hs_new_view_msg(hs_new_view_message msg) = 0; + + //inbound communications + virtual void on_hs_vote_msg(hs_vote_message msg) = 0; //confirmation msg event handler + virtual void on_hs_proposal_msg(hs_proposal_message msg) = 0; //consensus msg event handler + virtual void on_hs_new_view_msg(hs_new_view_message msg) = 0; //new view msg event handler + virtual void on_hs_new_block_msg(hs_new_block_message msg) = 0; //new block msg event handler + + }; + +}} \ No newline at end of file diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp new file mode 100644 index 0000000000..6442c97885 --- /dev/null +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -0,0 +1,56 @@ +#pragma once +#include +#include + +#include + +namespace eosio { namespace hotstuff { + + class chain_pacemaker : public base_pacemaker { + + public: + + //class-specific functions + + void init(controller* chain); + + std::mutex _hotstuff_state_mutex; + + //base_pacemaker interface functions + + name get_proposer(); + name get_leader() ; + name get_next_leader() ; + std::vector get_finalizers(); + + block_id_type get_current_block_id(); + + uint32_t get_quorum_threshold(); + + void register_listener(name name, qc_chain& qcc); + void unregister_listener(name name); + + void beat(); + + void send_hs_proposal_msg(hs_proposal_message msg); + void send_hs_vote_msg(hs_vote_message msg); + void send_hs_new_block_msg(hs_new_block_message msg); + void send_hs_new_view_msg(hs_new_view_message msg); + + void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler + void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler + void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler + + + private : + + chain::controller* _chain = NULL; + + qc_chain* _qc_chain = NULL; + + uint32_t _quorum_threshold = 15; //todo : calculate from schedule + + }; + +}} \ No newline at end of file diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp new file mode 100644 index 0000000000..87e304fc61 --- /dev/null +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -0,0 +1,176 @@ +#pragma once +#include +//#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include + +namespace eosio { namespace hotstuff { + + using boost::multi_index_container; + using namespace boost::multi_index; + + using namespace eosio::chain; + + //const uint32_t INTERUPT_TIMEOUT = 6; //sufficient timeout for new leader to be selected + + class qc_chain { + public: + + static void handle_eptr(std::exception_ptr eptr){ + try { + if (eptr) { + std::rethrow_exception(eptr); + } + } catch(const std::exception& e) { + ilog("Caught exception ${ex}" , ("ex", e.what())); + std::exit(0); + } + }; + + qc_chain(){}; + ~qc_chain(){ + +/* if (_pacemaker == NULL) delete _pacemaker; + + _pacemaker = 0;*/ + + }; + + //todo : remove. bls12-381 key used for testing purposes + std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; + + fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); + + enum msg_type { + new_view = 1, + new_block = 2, + qc = 3, + vote = 4 + }; + + uint32_t _v_height; + + bool _chained_mode = false ; + + const block_id_type NULL_BLOCK_ID = block_id_type("00"); + const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); + + fc::sha256 _b_leaf = NULL_PROPOSAL_ID; + fc::sha256 _b_lock = NULL_PROPOSAL_ID; + fc::sha256 _b_exec = NULL_PROPOSAL_ID; + + block_id_type _block_exec = NULL_BLOCK_ID; + + eosio::chain::quorum_certificate _high_qc; + eosio::chain::quorum_certificate _current_qc; + + eosio::chain::extended_schedule _schedule; + + std::set _my_producers; + + block_id_type _pending_proposal_block = NULL_BLOCK_ID; + + struct by_proposal_id{}; + struct by_proposal_height{}; + + typedef multi_index_container< + hs_proposal_message, + indexed_by< + hashed_unique< + tag, + BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) + >, + ordered_unique< + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) + > + > + > proposal_store_type; + + proposal_store_type _proposal_store; + + //uint32_t _threshold = 15; + + digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc); + + void reset_qc(fc::sha256 proposal_id); + + bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal); + + name get_proposer(); + name get_leader(); + name get_incoming_leader(); + + bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); + + std::vector get_finalizers(); + + hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); + hs_new_block_message new_block_candidate(block_id_type block_id); + + void init(name id, base_pacemaker& pacemaker, std::set my_producers); + + bool am_i_proposer(); + bool am_i_leader(); + bool am_i_finalizer(); + + void process_proposal(hs_proposal_message msg); + void process_vote(hs_vote_message msg); + void process_new_view(hs_new_view_message msg); + void process_new_block(hs_new_block_message msg); + + bool extends(fc::sha256 descendant, fc::sha256 ancestor); + + void on_beat(); + + void update_high_qc(eosio::chain::quorum_certificate high_qc); + + void on_leader_rotate(); + + bool is_node_safe(hs_proposal_message proposal); + + std::vector get_qc_chain(fc::sha256 proposal_id); + + void send_hs_proposal_msg(hs_proposal_message msg); + void send_hs_vote_msg(hs_vote_message msg); + void send_hs_new_view_msg(hs_new_view_message msg); + void send_hs_new_block_msg(hs_new_block_message msg); + + void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler + void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler + void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler + + void update(hs_proposal_message proposal); + void commit(hs_proposal_message proposal); + + void gc_proposals(uint64_t cutoff); + + + private : + + name _id; + + base_pacemaker* _pacemaker = NULL; + + }; +}} /// eosio::qc_chain \ No newline at end of file diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp new file mode 100644 index 0000000000..9997302080 --- /dev/null +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -0,0 +1,123 @@ +#pragma once +#include +#include + +namespace eosio { namespace hotstuff { + + class test_pacemaker : public base_pacemaker { + + public: + + //class-specific functions + + class indexed_qc_chain{ + + public: + + name _name; + + bool _active = true; + + qc_chain* _qc_chain = NULL; //todo : use smart pointer + + uint64_t by_name()const{return _name.to_uint64_t();}; + + ~indexed_qc_chain(){ + + //if (_qc_chain == NULL) delete _qc_chain; + + //_qc_chain = NULL; + + }; + + }; + + struct by_name_id{}; + + typedef multi_index_container< + indexed_qc_chain, + indexed_by< + ordered_unique< + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(indexed_qc_chain, uint64_t, by_name) + > + > + > qc_chain_type; + + qc_chain_type _qcc_store; + + +/* void send_hs_proposal_msg(hs_proposal_message msg); + void send_hs_vote_msg(hs_vote_message msg); + void send_hs_new_block_msg(hs_new_block_message msg); + void send_hs_new_view_msg(hs_new_view_message msg);*/ + + using hotstuff_message = std::variant; + + //void init(std::vector unique_replicas); + + void set_proposer(name proposer); + + void set_leader(name leader); + + void set_next_leader(name next_leader); + + void set_finalizers(std::vector finalizers); + + void set_current_block_id(block_id_type id); + + void set_quorum_threshold(uint32_t threshold); + + void propagate(); + + //indexed_qc_chain get_qc_chain(name replica); + + //~test_pacemaker(){}; + + //base_pacemaker interface functions + + name get_proposer(); + name get_leader(); + name get_next_leader(); + std::vector get_finalizers(); + + block_id_type get_current_block_id(); + + uint32_t get_quorum_threshold(); + + void register_listener(name name, qc_chain& qcc); + void unregister_listener(name name); + + void beat(); + + void send_hs_proposal_msg(hs_proposal_message msg); + void send_hs_vote_msg(hs_vote_message msg); + void send_hs_new_block_msg(hs_new_block_message msg); + void send_hs_new_view_msg(hs_new_view_message msg); + + void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler + void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler + void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler + + private : + + std::vector _message_queue; + std::vector _pending_message_queue; + + name _proposer; + name _leader; + name _next_leader; + + std::vector _finalizers; + + block_id_type _current_block_id; + + std::vector _unique_replicas; + + uint32_t _quorum_threshold = 15; //todo : calculate from schedule + + + }; + +}} \ No newline at end of file diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp new file mode 100644 index 0000000000..50d220a291 --- /dev/null +++ b/libraries/hotstuff/qc_chain.cpp @@ -0,0 +1,1073 @@ +#include + + +//todo list / notes : + +/* + + + +fork tests in unittests + + + +network plugin versioning + +handshake_message.network_version + +independant of protocol feature activation + + + +separate library for hotstuff (look at SHIP libray used by state history plugin ) + + +boost tests producer plugin test + + + +regression tests python framework as a base + + + +performance testing + + + + +*/ + + + +// +// complete proposer / leader differentiation +// integration with new bls implementation +// +// hotstuff as a library with its own tests (model on state history plugin + state_history library ) +// +// unit / integration tests -> producer_plugin + fork_tests tests as a model +// +// test deterministic sequence +// +// test non-replica participation +// test finality vioaltion +// test loss of liveness +// +// test split chain +// +// integration with fork_db / LIB overhaul +// +// integration with performance testing +// +// regression testing ci/cd -> python regression tests +// +// add APIs for proof data +// +// add election proposal in block header +// +// map proposers / finalizers / leader to new host functions +// +// support pause / resume producer +// +// keep track of proposals sent to peers +// +// allow syncing of proposals +// +// versioning of net protocol version +// +// protocol feature activation HOTSTUFF_CONSENSUS +// +// system contract update 1 -> allow BPs to register + prove their aggregate pub key. Allow existing BPs to unreg + reg without new aggregate key. Prevent new BPs from registering without proving aggregate pub key +// +// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available +// +// + + +namespace eosio { namespace hotstuff { + + + digest_type qc_chain::get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ + + digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); + digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); + + return h2; + + } + + std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ + + std::vector ret_arr; + + proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); + + b_2_itr = _proposal_store.get().find( proposal_id ); + if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); + if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); + + if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); + if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); + if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); + + return ret_arr; + + } + + hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { + + hs_proposal_message b_new; + + b_new.block_id = block_id; + b_new.parent_id = _b_leaf; + b_new.phase_counter = phase_counter; + + b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + + if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ + + std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + if (chain_length>=2){ + + auto itr = current_qc_chain.begin(); + + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + + if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; + else { + + proposal_store_type::nth_index<0>::type::iterator p_itr; + + p_itr = _proposal_store.get().find( b1.parent_id ); + + b_new.final_on_qc = p_itr->final_on_qc; + + } + + } + + } + + b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); + + ilog("=== creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + ("block_num", b_new.block_num()) + ("phase_counter", b_new.phase_counter) + ("proposal_id", b_new.proposal_id) + ("parent_id", b_new.parent_id) + ("justify", b_new.justify.proposal_id)); + + return b_new; + + } + + void qc_chain::reset_qc(fc::sha256 proposal_id){ + + _current_qc.proposal_id = proposal_id; + _current_qc.quorum_met = false; + _current_qc.active_finalizers = {}; + _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); + + } + + hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { + + hs_new_block_message b; + + b.block_id = block_id; + b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + + return b; + } + + bool qc_chain::evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ + + if (finalizers.size() < _pacemaker->get_quorum_threshold()){ + return false; + } + + fc::crypto::blslib::bls_public_key agg_key; + + for (int i = 0; i < finalizers.size(); i++) { + + //adding finalizer's key to the aggregate pub key + if (i==0) agg_key = _private_key.get_public_key(); + else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); + + } + + fc::crypto::blslib::bls_signature justification_agg_sig; + + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; + + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); + + return ok; + + } + + bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ + + if (qc.quorum_met == true ) { + return true; //skip evaluation if we've already verified quorum was met + } + else { + + //ilog("qc : ${qc}", ("qc", qc)); + + bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); + + qc.quorum_met = quorum_met; + + return qc.quorum_met ; + + } + + } + + void qc_chain::init(name id, base_pacemaker& pacemaker, std::set my_producers){ + + _id = id; + + _pacemaker = &pacemaker; + + _my_producers = my_producers; + + _pacemaker->register_listener(id, *this); + + ilog(" === qc chain initialized ${my_producers}", ("my_producers", my_producers)); + + //auto itr = _my_producers.begin(); + + //ilog("bla"); + + //ilog("name ${name}", ("name", *itr)); + + //ilog("111"); + + } + + bool qc_chain::am_i_proposer(){ + + //ilog("am_i_proposer"); + + name proposer = _pacemaker->get_proposer(); + + //ilog("Proposer : ${proposer}", ("proposer", proposer)); + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); + + //ilog("Found"); + + if (prod_itr==_my_producers.end()) return false; + else return true; + + } + + bool qc_chain::am_i_leader(){ + + //ilog("am_i_leader"); + + name leader = _pacemaker->get_leader(); + + //ilog("Leader : ${leader}", ("leader", leader)); + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); + + if (prod_itr==_my_producers.end()) return false; + else return true; + + } + + bool qc_chain::am_i_finalizer(){ + + //ilog("am_i_finalizer"); + + std::vector finalizers = _pacemaker->get_finalizers(); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + name n = *mf_itr; + + auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f == n; }); + + if (prod_itr!=finalizers.end()) return true; + + mf_itr++; + + } + + return false; + + } + + void qc_chain::process_proposal(hs_proposal_message proposal){ + + + auto itr = _proposal_store.get().find( proposal.proposal_id ); + + if (itr != _proposal_store.get().end()) { + ilog("*** proposal received twice : ${proposal_id}",("proposal_id", proposal.proposal_id)); + return ; //already aware of proposal, nothing to do + + } + + ilog("=== received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id) + ("parent_id", proposal.parent_id) + ("justify", proposal.justify.proposal_id)); + + _proposal_store.insert(proposal); //new proposal + + bool am_finalizer = am_i_finalizer(); + bool node_safe = is_node_safe(proposal); + + bool signature_required = am_finalizer && node_safe; + + //if I am a finalizer for this proposal, test safenode predicate for possible vote + if (signature_required){ + + //ilog("signature required"); + + _v_height = proposal.get_height(); + + fc::crypto::blslib::bls_signature agg_sig; + + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; + + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + //iterate over all my finalizers and sign / broadcast for each that is in the schedule + std::vector finalizers = _pacemaker->get_finalizers(); + + //ilog("signed proposal. Broadcasting for each of my producers"); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find(finalizers.begin(), finalizers.end(), *mf_itr); + + if (prod_itr!=finalizers.end()) { + + fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer + + name n = *prod_itr; + + hs_vote_message v_msg = {proposal.proposal_id, n, sig}; + + send_hs_vote_msg(v_msg); + + }; + + mf_itr++; + + } + + } + + //update internal state + update(proposal); + + //check for leader change + on_leader_rotate(); + + //ilog("process_proposal end"); + + } + + void qc_chain::process_vote(hs_vote_message vote){ + + //check for duplicate or invalid vote, return in either case + //abstracted [...] + + bool am_leader = am_i_leader(); //am I leader? + + if(!am_leader) return; + + //ilog("=== Process vote from ${finalizer}", ("finalizer", vote.finalizer)); + + //only leader need to take action on votes + + if (vote.proposal_id != _current_qc.proposal_id) return; + + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); + + if (p_itr==_proposal_store.get().end()){ + ilog("*** couldn't find proposal"); + + ilog("*** vote : ${vote}", ("vote", vote)); + + return; + } + + bool quorum_met = _current_qc.quorum_met; //check if quorum already met + + if (!quorum_met){ + + _current_qc.active_finalizers.push_back(vote.finalizer); + + if (_current_qc.active_finalizers.size()>1) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); + else _current_qc.active_agg_sig = vote.sig; + + quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); + + if (quorum_met){ + + _current_qc.quorum_met = true; + + //ilog("=== Quorum met on #${block_num} ${proposal_id} ", ("block_num", p_itr->block_num())("proposal_id", vote.proposal_id)); + + //ilog("=== update_high_qc : _current_qc ==="); + update_high_qc(_current_qc); + + //check for leader change + on_leader_rotate(); + + + //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet + if (_chained_mode==false && p_itr->phase_counter<3){ + + hs_proposal_message proposal_candidate; + + if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); + else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); + + reset_qc(proposal_candidate.proposal_id); + + _pending_proposal_block = NULL_BLOCK_ID; + + send_hs_proposal_msg(proposal_candidate); + + _b_leaf = proposal_candidate.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + + } + + } + + } + + } + + void qc_chain::process_new_view(hs_new_view_message new_view){ + + ilog("=== process_new_view === ${qc}", ("qc", new_view.high_qc)); + update_high_qc(new_view.high_qc); + + } + + void qc_chain::process_new_block(hs_new_block_message msg){ + + //ilog("=== Process new block ==="); + + } + + void qc_chain::send_hs_proposal_msg(hs_proposal_message msg){ + + //ilog("=== broadcast_hs_proposal ==="); + + //hs_proposal_message_ptr ptr = std::make_shared(msg); + + _pacemaker->send_hs_proposal_msg(msg); + + process_proposal(msg); + + } + + + void qc_chain::send_hs_vote_msg(hs_vote_message msg){ + + //ilog("=== broadcast_hs_vote ==="); + + //hs_vote_message_ptr ptr = std::make_shared(msg); + + _pacemaker->send_hs_vote_msg(msg); + + process_vote(msg); + + } + + void qc_chain::send_hs_new_view_msg(hs_new_view_message msg){ + + //ilog("=== broadcast_hs_new_view ==="); + + //hs_new_view_message_ptr ptr = std::make_shared(msg); + + _pacemaker->send_hs_new_view_msg(msg); + + } + + void qc_chain::send_hs_new_block_msg(hs_new_block_message msg){ + + //ilog("=== broadcast_hs_new_block ==="); + + //hs_new_block_message_ptr ptr = std::make_shared(msg); + + _pacemaker->send_hs_new_block_msg(msg); + + } + + //extends predicate + bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ + + //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified + + proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); + + uint32_t counter = 0; + + while (itr!=_proposal_store.get().end()){ + + itr = _proposal_store.get().find(itr->parent_id ); + + if (itr->proposal_id == ancestor){ + if (counter>25) { + ilog("***"); + ilog("*** took ${counter} iterations to find ancestor ", ("counter", counter)); + ilog("***"); + + } + return true; + } + + counter++; + + } + + ilog(" ***** extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", + ("d_proposal_id", descendant) + ("a_proposal_id", ancestor)); + + return false; + + } + + void qc_chain::on_beat(){ +std::exception_ptr eptr; +try{ + + ilog("=== on beat ==="); + + //std::lock_guard g( this-> _hotstuff_state_mutex ); + + name current_producer = _pacemaker->get_leader(); + + if (current_producer == "eosio"_n) return; + + //ilog("current_producer : ${current_producer}", ("current_producer", current_producer)); + + block_id_type current_block_id = _pacemaker->get_current_block_id(); + + //ilog("current_block_id : ${current_block_id}", ("current_block_id", current_block_id)); + + //ilog(" === qc chain on_beat ${my_producers}", ("my_producers", _my_producers)); + + //ilog("222"); + + bool am_proposer = am_i_proposer(); + + //ilog("am i proposer received"); + + bool am_leader = am_i_leader(); + + //ilog("=== am_proposer = ${am_proposer}", ("am_proposer", am_proposer)); + //ilog("=== am_leader = ${am_leader}", ("am_leader", am_leader)); + + if (!am_proposer && !am_leader){ + + return; //nothing to do + + } + + //if I am the leader + if (am_leader){ + + //if I'm not also the proposer, perform block validation as required + if (!am_proposer){ + + //todo : extra validation? + + } + + + if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ + + _pending_proposal_block = current_block_id; + + } + else { + + hs_proposal_message proposal_candidate = new_proposal_candidate(current_block_id, 0 ); + + reset_qc(proposal_candidate.proposal_id); + + _pending_proposal_block = NULL_BLOCK_ID; + + send_hs_proposal_msg(proposal_candidate); + + _b_leaf = proposal_candidate.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + + } + + } + else { + + //if I'm only a proposer and not the leader, I send a new block message + + hs_new_block_message block_candidate = new_block_candidate(current_block_id); + + //ilog("=== broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); + + send_hs_new_block_msg(block_candidate); + + } + + //ilog(" === end of on_beat"); +} +catch (...){ + ilog("error during on_beat"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ + + //ilog("=== check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); + + // if new high QC is higher than current, update to new + + + if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ + + _high_qc = high_qc; + _b_leaf = _high_qc.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + + } + else { + + proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; + proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; + + old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); + new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); + + if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); + if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); + + + if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ + + bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); + + if (quorum_met){ + + high_qc.quorum_met = true; + + //ilog("=== updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); + + _high_qc = high_qc; + _b_leaf = _high_qc.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + + } + + } + + } + + } + + void qc_chain::on_leader_rotate(){ + + //ilog("on_leader_rotate"); + + //verify if leader changed + + name current_leader = _pacemaker->get_leader() ; + name next_leader = _pacemaker->get_next_leader() ; + + if (current_leader != next_leader){ + + ilog("/// rotating leader : ${old_leader} -> ${new_leader} ", + ("old_leader", current_leader)("new_leader", next_leader)); + + //leader changed, we send our new_view message + + reset_qc(NULL_PROPOSAL_ID); + + _pending_proposal_block = NULL_BLOCK_ID; + + hs_new_view_message new_view; + + new_view.high_qc = _high_qc; + + send_hs_new_view_msg(new_view); + } + + + } + + //safenode predicate + bool qc_chain::is_node_safe(hs_proposal_message proposal){ + + //ilog("=== is_node_safe ==="); + + bool monotony_check = false; + bool safety_check = false; + bool liveness_check = false; + bool final_on_qc_check = false; + + fc::sha256 upcoming_commit; + + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated + else { + + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + if (chain_length>=2){ + + auto itr = current_qc_chain.begin(); + + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + + if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; + else { + + proposal_store_type::nth_index<0>::type::iterator p_itr; + + p_itr = _proposal_store.get().find( b1.parent_id ); + + upcoming_commit = p_itr->final_on_qc; + + } + + } + + //abstracted [...] + if (upcoming_commit == proposal.final_on_qc){ + final_on_qc_check = true; + } + + } + + if (proposal.get_height() > _v_height){ + monotony_check = true; + } + + if (_b_lock != NULL_PROPOSAL_ID){ + + //Safety check : check if this proposal extends the chain I'm locked on + if (extends(proposal.proposal_id, _b_lock)){ + safety_check = true; + } + + //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated + else { + + proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); + proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); + + if (prop_justification->get_height() > b_lock->get_height()){ + liveness_check = true; + } + } + + } + else { + + ilog("not locked on anything, liveness and safety are true"); + + //if we're not locked on anything, means the protocol just activated or chain just launched + liveness_check = true; + safety_check = true; + } + +/* ilog("=== final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", + ("final_on_qc_check", final_on_qc_check) + ("monotony_check", monotony_check) + ("liveness_check", liveness_check) + ("safety_check", safety_check));*/ + + return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully + + } + + //on proposal received, called from network thread + void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== ${id} qc on_hs_proposal_msg ===", ("id", _id)); + + //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_proposal(msg); + + //ilog(" === end of on_hs_proposal_msg"); +} +catch (...){ + ilog("error during on_hs_proposal_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + //on vote received, called from network thread + void qc_chain::on_hs_vote_msg(hs_vote_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== ${id} qc on_hs_vote_msg ===", ("id", _id)); + + //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_vote(msg); + + //ilog(" === end of on_hs_vote_msg"); + } +catch (...){ + ilog("error during on_hs_vote_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + //on new view received, called from network thread + void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== ${id} qc on_hs_new_view_msg ===", ("id", _id)); + + //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_new_view(msg); + + //ilog(" === end of on_hs_new_view_msg"); +} +catch (...){ + ilog("error during on_hs_new_view_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + //on new block received, called from network thread + void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== ${id} qc on_hs_new_block_msg ===", ("id", _id)); + + //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_new_block(msg); + + //ilog(" === end of on_hs_new_block_msg"); +} +catch (...){ + ilog("error during on_hs_new_block_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + void qc_chain::update(hs_proposal_message proposal){ + + //ilog("=== update internal state ==="); + + proposal_store_type::nth_index<0>::type::iterator b_lock; + + //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ + ilog("*** proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)); + return; + } + + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + b_lock = _proposal_store.get().find( _b_lock); + + //ilog("=== update_high_qc : proposal.justify ==="); + update_high_qc(proposal.justify); + + if (chain_length<1){ + ilog("*** qc chain length is 0"); + return; + } + + auto itr = current_qc_chain.begin(); + hs_proposal_message b_2 = *itr; + + if (chain_length<2){ + ilog("*** qc chain length is 1"); + return; + } + + itr++; + + hs_proposal_message b_1 = *itr; + + //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock + if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ + + //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); + _b_lock = b_1.proposal_id; //commit phase on b1 + + ilog("=== _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)); + + } + + if (chain_length<3){ + ilog("*** qc chain length is 2"); + return; + } + + itr++; + + hs_proposal_message b = *itr; + +/* ilog("direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", + ("b_2.parent_id",b_2.parent_id) + ("b_1.proposal_id", b_1.proposal_id) + ("b_1.parent_id", b_1.parent_id) + ("b.proposal_id", b.proposal_id));*/ + + //direct parent relationship verification + if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ + + //ilog("direct parent relationship verified"); + + + commit(b); + + //ilog("last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); + + //ilog("setting _b_exec to ${proposal_id}", ("proposal_id",b.proposal_id )); + _b_exec = b.proposal_id; //decide phase on b + _block_exec = b.block_id; + + gc_proposals( b.get_height()-1); + + //ilog("completed commit"); + + } + else { + + ilog("*** could not verify direct parent relationship"); + + ilog("*** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); + ilog("*** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); + ilog("*** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); + + } + + + } + + void qc_chain::gc_proposals(uint64_t cutoff){ + + //ilog("garbage collection on old data"); + + auto end_itr = _proposal_store.get().upper_bound(cutoff); + + while (_proposal_store.get().begin() != end_itr){ + + auto itr = _proposal_store.get().begin(); + + ilog("erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + ("block_num", itr->block_num()) + ("phase_counter", itr->phase_counter) + ("block_id", itr->block_id) + ("proposal_id", itr->proposal_id)); + + _proposal_store.get().erase(itr); + + + } + + } + + void qc_chain::commit(hs_proposal_message proposal){ + +/* ilog("=== attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", proposal.block_num()) + ("proposal_id", proposal.proposal_id) + ("block_id", proposal.block_id) + ("phase_counter", proposal.phase_counter) + ("parent_id", proposal.parent_id)); + */ + bool sequence_respected = false; + + proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); + +/* ilog("=== _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", last_exec_prop->block_num()) + ("proposal_id", last_exec_prop->proposal_id) + ("block_id", last_exec_prop->block_id) + ("phase_counter", last_exec_prop->phase_counter) + ("parent_id", last_exec_prop->parent_id));*/ + + if (_b_exec==NULL_PROPOSAL_ID){ + //ilog("first block committed"); + sequence_respected = true; + } + else sequence_respected = last_exec_prop->get_height() < proposal.get_height(); + + if (sequence_respected){ + + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); + + if (p_itr != _proposal_store.get().end()){ + + //ilog("=== recursively committing" ); + + commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first + + } + + ilog("=== committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("block_id", proposal.block_id) + ("proposal_id", proposal.proposal_id)); + + } + + } + +}} + + diff --git a/libraries/hotstuff/test/CMakeLists.txt b/libraries/hotstuff/test/CMakeLists.txt new file mode 100644 index 0000000000..20a940b112 --- /dev/null +++ b/libraries/hotstuff/test/CMakeLists.txt @@ -0,0 +1,4 @@ +add_executable( test_hotstuff test_hotstuff.cpp) +target_link_libraries( test_hotstuff hotstuff fc Boost::unit_test_framework) + +add_test(NAME test_hotstuff COMMAND test_hotstuff WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/libraries/hotstuff/test/Testing/Temporary/CTestCostData.txt b/libraries/hotstuff/test/Testing/Temporary/CTestCostData.txt new file mode 100644 index 0000000000..ed97d539c0 --- /dev/null +++ b/libraries/hotstuff/test/Testing/Temporary/CTestCostData.txt @@ -0,0 +1 @@ +--- diff --git a/libraries/hotstuff/test/Testing/Temporary/LastTest.log b/libraries/hotstuff/test/Testing/Temporary/LastTest.log new file mode 100644 index 0000000000..a144c6eee8 --- /dev/null +++ b/libraries/hotstuff/test/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Mar 09 14:59 UTC +---------------------------------------------------------- +End testing: Mar 09 14:59 UTC diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp new file mode 100644 index 0000000000..b2084487dc --- /dev/null +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -0,0 +1,166 @@ +#define BOOST_TEST_MODULE hotstuff +#include + +#include + +#include + +#include +#include + +#include + +using namespace eosio::hotstuff; + +using std::cout; + +std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; + +fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); + + +fc::sha256 message_1 = fc::sha256("000000000000000118237d3d79f3c684c031a9844c27e6b95c6d27d8a5f401a1"); +fc::sha256 message_2 = fc::sha256("0000000000000002fb2129a8f7c9091ae983bc817002ffab21cd98eab2147029"); + + + +BOOST_AUTO_TEST_SUITE(hotstuff) + +BOOST_AUTO_TEST_CASE(hotstuff_tests) try { + + std::vector ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c39"), + block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530684"), + block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf330"), + block_id_type("00000004235f391d91d5da938cfa8c4738d92da6c007da596f1db05c37d38866"), + block_id_type("00000005485fa018c16b6150aed839bdd4cbc2149f70191e89f2b19fe711b1c0"), + block_id_type("00000006161b9c79797059bbdcbf49614bbdca33d35b8099ffa250583dc41d9d"), + block_id_type("00000007ffd04a602236843f842827c2ac2aa61d586b7ebc8cc3c276921b55d9"), + block_id_type("000000085e8b9b158801fea3f7b2b627734805b9192568b67d7d00d676e427e3"), + block_id_type("0000000979b05f273f2885304f952aaa6f47d56985e003ec35c22472682ad3a2"), + block_id_type("0000000a703d6a104c722b8bc2d7227b90a35d08835343564c2fd66eb9dcf999"), + block_id_type("0000000ba7ef2e432d465800e53d1da982f2816c051153f9054960089d2f37d8") }; + + //list of unique replicas for our test + std::vector unique_replicas{ "bpa"_n, "bpb"_n, "bpc"_n, + "bpd"_n, "bpe"_n, "bpf"_n, + "bpg"_n, "bph"_n, "bpi"_n, + "bpj"_n, "bpk"_n ,"bpl"_n, + "bpm"_n, "bpn"_n, "bpo"_n, + "bpp"_n, "bpq"_n, "bpr"_n, + "bps"_n, "bpt"_n, "bpu"_n }; + + std::vector> qc_chains; + + test_pacemaker tpm; + + std::cout << "Running Hotstuff Tests..." << "\n"; + + for (name r : unique_replicas){ + + qc_chains.push_back(std::make_pair(r, qc_chain())); + + } + + int counter = 0; + + auto itr = qc_chains.begin(); + + while (itr!=qc_chains.end()){ + + itr->second.init(unique_replicas[counter], tpm, {unique_replicas[counter]}); + + itr++; + counter++; + + } + + tpm.set_proposer("bpa"_n); + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); + + std::cout << "test_pacemaker configured." << "\n"; + + tpm.set_current_block_id(ids[0]); + + std::cout << "test_pacemaker got qcc" << "\n"; + + auto qc = std::find_if(qc_chains.begin(), qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + + tpm.beat(); + + std::cout << "test_pacemaker on_beat event chain executed." << "\n"; + + tpm.propagate(); //propagating new proposal message + + std::cout << " --- propagated new proposal message (phase 0)." << "\n"; + + tpm.propagate(); //propagating votes on new proposal + + std::cout << " --- propagated votes on new proposal." << "\n"; + + qc_chain::proposal_store_type::nth_index<0>::type::iterator prop_itr = qc->second._proposal_store.get().find( qc->second._high_qc.proposal_id ); + + std::cout << "bpa current high_qc is : " << qc->second._high_qc.proposal_id.str() << ",id : " << prop_itr->block_id.str() << ", phase : " << unsigned(prop_itr->phase_counter) << "\n"; + + std::cout << "bpa current _b_leaf is : " << qc->second._b_leaf.str() << "\n"; + std::cout << "bpa current _b_lock is : " << qc->second._b_lock.str() << "\n"; + std::cout << "bpa current _b_exec is : " << qc->second._b_exec.str() << "\n"; + + tpm.propagate(); //propagating updated proposal with qc + + std::cout << " --- propagated propagating updated proposal with qc (phase 1)." << "\n"; + + tpm.propagate(); //propagating votes on new proposal + + std::cout << " --- propagated votes on new proposal." << "\n"; + + prop_itr = qc->second._proposal_store.get().find( qc->second._high_qc.proposal_id ); + + std::cout << "bpa current high_qc is : " << qc->second._high_qc.proposal_id.str() << ",id : " << prop_itr->block_id.str() << ", phase : " << unsigned(prop_itr->phase_counter) << "\n"; + + std::cout << "bpa current _b_leaf is : " << qc->second._b_leaf.str() << "\n"; + std::cout << "bpa current _b_lock is : " << qc->second._b_lock.str() << "\n"; + std::cout << "bpa current _b_exec is : " << qc->second._b_exec.str() << "\n"; + + tpm.propagate(); //propagating updated proposal with qc + + std::cout << " --- propagated propagating updated proposal with qc (phase 2)." << "\n"; + + tpm.propagate(); //propagating votes on new proposal + + std::cout << " --- propagated votes on new proposal." << "\n"; + + prop_itr = qc->second._proposal_store.get().find( qc->second._high_qc.proposal_id ); + + std::cout << "bpa current high_qc is : " << qc->second._high_qc.proposal_id.str() << ",id : " << prop_itr->block_id.str() << ", phase : " << unsigned(prop_itr->phase_counter) << "\n"; + + std::cout << "bpa current _b_leaf is : " << qc->second._b_leaf.str() << "\n"; + std::cout << "bpa current _b_lock is : " << qc->second._b_lock.str() << "\n"; + std::cout << "bpa current _b_exec is : " << qc->second._b_exec.str() << "\n"; + + tpm.propagate(); //propagating updated proposal with qc + + std::cout << " --- propagated propagating updated proposal with qc (phase 3)." << "\n"; + + tpm.propagate(); //propagating votes on new proposal + + std::cout << " --- propagated votes on new proposal." << "\n"; + + prop_itr = qc->second._proposal_store.get().find( qc->second._high_qc.proposal_id ); + + std::cout << "bpa current high_qc is : " << qc->second._high_qc.proposal_id.str() << ",id : " << prop_itr->block_id.str() << ", phase : " << unsigned(prop_itr->phase_counter) << "\n"; + + std::cout << "bpa current _b_leaf is : " << qc->second._b_leaf.str() << "\n"; + std::cout << "bpa current _b_lock is : " << qc->second._b_lock.str() << "\n"; + std::cout << "bpa current _b_exec is : " << qc->second._b_exec.str() << "\n"; + + //std::cout << "test_pacemaker messages propagated." << "\n"; + + BOOST_CHECK_EQUAL(false, false); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_SUITE_END() diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test_pacemaker.cpp new file mode 100644 index 0000000000..01ff62862f --- /dev/null +++ b/libraries/hotstuff/test_pacemaker.cpp @@ -0,0 +1,303 @@ +#include +#include + +namespace eosio { namespace hotstuff { + +/* void test_pacemaker::init(std::vector unique_replicas){ + + for (name r : unique_replicas){ + + std::set mp{r}; + + register_listener(r, qcc); + + } + + _unique_replicas = unique_replicas; + + };*/ + + void test_pacemaker::set_proposer(name proposer){ + _proposer = proposer; + }; + + void test_pacemaker::set_leader(name leader){ + _leader = leader; + }; + + void test_pacemaker::set_next_leader(name next_leader){ + _next_leader = next_leader; + }; + + void test_pacemaker::set_finalizers(std::vector finalizers){ + _finalizers = finalizers; + }; + + void test_pacemaker::set_current_block_id(block_id_type id){ + _current_block_id = id; + }; + + void test_pacemaker::set_quorum_threshold(uint32_t threshold){ + _quorum_threshold = threshold; + } + + void test_pacemaker::propagate(){ + + int count = 1; + + ilog(" === propagate ${count} messages", ("count", _pending_message_queue.size())); + + _message_queue = _pending_message_queue; + + while (_pending_message_queue.begin()!=_pending_message_queue.end()){ + + auto itr = _pending_message_queue.end(); + itr--; + + _pending_message_queue.erase(itr); + + } + + //ilog(" === propagate ${count} messages", ("count", _message_queue.size())); + + auto msg_itr = _message_queue.begin(); + + while (msg_itr!=_message_queue.end()){ + + ilog(" === propagating message ${count} : type : ${index}", ("count", count) ("index", msg_itr->index())); + + if (msg_itr->index() == 0) on_hs_proposal_msg(std::get(*msg_itr)); + else if (msg_itr->index() == 1) on_hs_vote_msg(std::get(*msg_itr)); + else if (msg_itr->index() == 2) on_hs_new_block_msg(std::get(*msg_itr)); + else if (msg_itr->index() == 3) on_hs_new_view_msg(std::get(*msg_itr)); + + + msg_itr++; + + //ilog(" === after erase"); + + count++; + + } + + //ilog(" === erase"); + + while (_message_queue.begin()!=_message_queue.end()){ + + auto itr = _message_queue.end(); + itr--; + + _message_queue.erase(itr); + + } + + //ilog(" === after erase"); + + ilog(" === end propagate"); + + } + + name test_pacemaker::get_proposer(){ + return _proposer; + }; + + name test_pacemaker::get_leader(){ + return _leader; + }; + + name test_pacemaker::get_next_leader(){ + return _next_leader; + }; + + std::vector test_pacemaker::get_finalizers(){ + return _finalizers; + }; + + block_id_type test_pacemaker::get_current_block_id(){ + return _current_block_id; + }; + + uint32_t test_pacemaker::get_quorum_threshold(){ + return _quorum_threshold; + }; + + void test_pacemaker::beat(){ + + auto itr = _qcc_store.get().find( _proposer.to_uint64_t() ); + + if (itr==_qcc_store.end()) throw std::runtime_error("proposer not found"); + + itr->_qc_chain->on_beat(); + + }; + + void test_pacemaker::register_listener(name name, qc_chain& qcc){ + + //ilog("reg listener"); + + auto itr = _qcc_store.get().find( name.to_uint64_t() ); + + //ilog("got itr"); + + if (itr!=_qcc_store.end()){ + + _qcc_store.modify(itr, [&]( auto& qcc ){ + qcc._active = true; + }); + + throw std::runtime_error("duplicate qc chain"); + + } + else { + + ilog("new listener ${name}", ("name", name)); + + //_unique_replicas.push_back(name); + + indexed_qc_chain iqcc; + + iqcc._name = name; + iqcc._active = true; + iqcc._qc_chain = &qcc; + + //ilog(" === register_listener 1 ${my_producers}", ("my_producers", iqcc._qc_chain->_my_producers)); + + _qcc_store.insert(iqcc); + + //ilog("aaadddd"); + + //auto itr = _qcc_store.get().find( name.to_uint64_t() ); + + //ilog(" === register_listener 2 ${my_producers}", ("my_producers", itr->_qc_chain->_my_producers)); + + + } + + + }; + + void test_pacemaker::unregister_listener(name name){ + + auto itr = _qcc_store.get().find( name.to_uint64_t() ); + + if (itr!= _qcc_store.end()) { + + _qcc_store.modify(itr, [&]( auto& qcc ){ + qcc._active = false; + }); + + } + else throw std::runtime_error("qc chain not found"); + + }; + + void test_pacemaker::send_hs_proposal_msg(hs_proposal_message msg){ + + //ilog("queuing hs_proposal_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); + + _pending_message_queue.push_back(msg); + + }; + + void test_pacemaker::send_hs_vote_msg(hs_vote_message msg){ + + //ilog("queuing hs_vote_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); + + _pending_message_queue.push_back(msg); + + }; + + void test_pacemaker::send_hs_new_block_msg(hs_new_block_message msg){ + + _pending_message_queue.push_back(msg); + + }; + + void test_pacemaker::send_hs_new_view_msg(hs_new_view_message msg){ + + _pending_message_queue.push_back(msg); + + }; + + void test_pacemaker::on_hs_proposal_msg(hs_proposal_message msg){ + + //ilog(" === on_hs_proposal_msg"); + auto qc_itr = _qcc_store.begin(); + + while (qc_itr!=_qcc_store.end()){ + + //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); + + if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + + if (qc_itr->_active) qc_itr->_qc_chain->on_hs_proposal_msg(msg); + + qc_itr++; + + } + + //ilog(" === end on_hs_proposal_msg"); + + } + + void test_pacemaker::on_hs_vote_msg(hs_vote_message msg){ + + //ilog(" === on_hs_vote_msg"); + auto qc_itr = _qcc_store.begin(); + + while (qc_itr!=_qcc_store.end()){ + + //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); + + if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + + if (qc_itr->_active) qc_itr->_qc_chain->on_hs_vote_msg(msg); + + qc_itr++; + } + + //ilog(" === end on_hs_vote_msg"); + + } + + void test_pacemaker::on_hs_new_block_msg(hs_new_block_message msg){ + + //ilog(" === on_hs_new_block_msg"); + auto qc_itr = _qcc_store.begin(); + + while (qc_itr!=_qcc_store.end()){ + + //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); + + if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + + if (qc_itr->_active) qc_itr->_qc_chain->on_hs_new_block_msg(msg); + + qc_itr++; + } + + //ilog(" === end on_hs_new_block_msg"); + + } + + void test_pacemaker::on_hs_new_view_msg(hs_new_view_message msg){ + + //ilog(" === on_hs_new_view_msg"); + auto qc_itr = _qcc_store.begin(); + + while (qc_itr!=_qcc_store.end()){ + + //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); + + if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + + if (qc_itr->_active) qc_itr->_qc_chain->on_hs_new_view_msg(msg); + + qc_itr++; + } + + //ilog(" === end on_hs_new_view_msg"); + + } + +}} \ No newline at end of file diff --git a/libraries/libfc/test/test_hotstuff.cpp.old b/libraries/libfc/test/test_hotstuff.cpp.old new file mode 100644 index 0000000000..4f2ad3060b --- /dev/null +++ b/libraries/libfc/test/test_hotstuff.cpp.old @@ -0,0 +1,106 @@ +#define BOOST_TEST_MODULE hotstuff +#include + +#include + +#include + +fc::sha256 message_1 = fc::sha256("000000000000000118237d3d79f3c684c031a9844c27e6b95c6d27d8a5f401a1"); +fc::sha256 message_2 = fc::sha256("0000000000000002fb2129a8f7c9091ae983bc817002ffab21cd98eab2147029"); + +struct proposal_height { + + fc::sha256 block_id; + + uint32_t phase_counter; + + int operator >(proposal_height x){ + if(block_id>x.block_id || (block_id==x.block_id && phase_counter>x.phase_counter )) return 1; + else return 0; + } + + int operator >=(proposal_height x){ + if(block_id>x.block_id || (block_id==x.block_id && phase_counter>=x.phase_counter )) return 1; + else return 0; + } + + int operator <(proposal_height x){ + return !(*this>=x); + } + + int operator <=(proposal_height x){ + return !(*this>x); + } + + int operator == (proposal_height x){ + if(block_id==x.block_id && phase_counter==x.phase_counter ) return 1; + else return 0; + } + + int operator != (proposal_height x){ + return !(*this==x); + } + + + +}; + +using std::cout; + +BOOST_AUTO_TEST_SUITE(hotstuff) + +BOOST_AUTO_TEST_CASE(hotstuff_1) try { + + proposal_height p1 = {message_1, 0}; + proposal_height p2 = {message_1, 0}; + + BOOST_CHECK_EQUAL(p1 > p2, false); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_2) try { + + proposal_height p1 = {message_1, 1}; + proposal_height p2 = {message_1, 0}; + + BOOST_CHECK_EQUAL(p1 > p2, true); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_3) try { + + proposal_height p1 = {message_1, 1}; + proposal_height p2 = {message_1, 1}; + + BOOST_CHECK_EQUAL(p1 <= p2, true); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_4) try { + + proposal_height p1 = {message_1, 1}; + proposal_height p2 = {message_2, 1}; + + BOOST_CHECK_EQUAL(p1 < p2, true); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_5) try { + + proposal_height p1 = {message_1, 1}; + proposal_height p2 = {message_1, 1}; + + BOOST_CHECK_EQUAL(p1 == p2, true); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_6) try { + + proposal_height p1 = {message_1, 1}; + proposal_height p2 = {message_1, 1}; + + BOOST_CHECK_EQUAL(p1 != p2, false); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_SUITE_END() diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp.bkp b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp.bkp new file mode 100644 index 0000000000..8b177295cf --- /dev/null +++ b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp.bkp @@ -0,0 +1,70 @@ +#pragma once +#include +#include +#include + +namespace eosio { namespace chain { + + const uint32_t INTERUPT_TIMEOUT = 6; //sufficient timeout for new leader to be selected + + class qc_chain { + public: + + qc_chain( ){}; + ~qc_chain(){}; + + name get_proposer(); + name get_leader(); + name get_incoming_leader(); + + bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); + + std::vector get_finalizers(); + + hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); + hs_new_block_message new_block_candidate(block_id_type block_id); + + void init(chain_plugin& chain_plug, std::set my_producers); + + block_header_state_ptr get_block_header( const block_id_type& id ); + + bool am_i_proposer(); + bool am_i_leader(); + bool am_i_finalizer(); + + void process_proposal(hs_proposal_message msg); + void process_vote(hs_vote_message msg); + void process_new_view(hs_new_view_message msg); + void process_new_block(hs_new_block_message msg); + + void broadcast_hs_proposal(hs_proposal_message msg); + void broadcast_hs_vote(hs_vote_message msg); + void broadcast_hs_new_view(hs_new_view_message msg); + void broadcast_hs_new_block(hs_new_block_message msg); + + bool extends(fc::sha256 descendant, fc::sha256 ancestor); + + void on_beat(block_state& hbs); + + void update_high_qc(eosio::chain::quorum_certificate high_qc); + + void on_leader_rotate(); + + bool is_node_safe(hs_proposal_message proposal); + + std::vector get_qc_chain(fc::sha256 proposal_id); + + void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler + void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler + void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler + + void update(hs_proposal_message proposal); + void commit(hs_proposal_message proposal); + + void clear_old_data(uint64_t cutoff); + + std::mutex _hotstuff_state_mutex; + + }; +}} /// eosio::qc_chain \ No newline at end of file diff --git a/plugins/producer_plugin/qc_chain.cpp.bkp b/plugins/producer_plugin/qc_chain.cpp.bkp new file mode 100644 index 0000000000..29290a3fc2 --- /dev/null +++ b/plugins/producer_plugin/qc_chain.cpp.bkp @@ -0,0 +1,1216 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include + +//todo list / notes : + +/* + + + +fork tests in unittests + + + +network plugin versioning + +handshake_message.network_version + +independant of protocol feature activation + + + +separate library for hotstuff (look at SHIP libray used by state history plugin ) + + +boost tests producer plugin test + + + +regression tests python framework as a base + + + +performance testing + + + + +*/ + + + +// +// complete proposer / leader differentiation +// integration with new bls implementation +// +// hotstuff as a library with its own tests (model on state history plugin + state_history library ) +// +// unit / integration tests -> producer_plugin + fork_tests tests as a model +// +// test deterministic sequence +// +// test non-replica participation +// test finality vioaltion +// test loss of liveness +// +// test split chain +// +// integration with fork_db / LIB overhaul +// +// integration with performance testing +// +// regression testing ci/cd -> python regression tests +// +// add APIs for proof data +// +// add election proposal in block header +// +// map proposers / finalizers / leader to new host functions +// +// support pause / resume producer +// +// keep track of proposals sent to peers +// +// allow syncing of proposals +// +// versioning of net protocol version +// +// protocol feature activation HOTSTUFF_CONSENSUS +// +// system contract update 1 -> allow BPs to register + prove their aggregate pub key. Allow existing BPs to unreg + reg without new aggregate key. Prevent new BPs from registering without proving aggregate pub key +// +// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available +// +// + + +namespace eosio { namespace chain { + using boost::multi_index_container; + using namespace boost::multi_index; + + //todo : remove. bls12-381 key used for testing purposes + std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; + + fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); + + enum msg_type { + new_view = 1, + new_block = 2, + qc = 3, + vote = 4 + }; + + uint32_t _v_height; + + bool _chained_mode = false ; + + void handle_eptr(std::exception_ptr eptr){ + try { + if (eptr) { + std::rethrow_exception(eptr); + } + } catch(const std::exception& e) { + ilog("Caught exception ${ex}" , ("ex", e.what())); + std::exit(0); + } + } + + const block_id_type NULL_BLOCK_ID = block_id_type("00"); + const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); + +/* const block_header_state_ptr NULL_BLOCK_HEADER_STATE_PTR = block_header_state_ptr(); + const block_state_ptr NULL_BLOCK_STATE_PTR = block_state_ptr();*/ + + fc::sha256 _b_leaf = NULL_PROPOSAL_ID; + fc::sha256 _b_lock = NULL_PROPOSAL_ID; + fc::sha256 _b_exec = NULL_PROPOSAL_ID; + + block_id_type _block_exec = NULL_BLOCK_ID; + + eosio::chain::quorum_certificate _high_qc; + eosio::chain::quorum_certificate _current_qc; + + eosio::chain::extended_schedule _schedule; + + chain_plugin* _chain_plug = nullptr; + std::set _my_producers; + + block_id_type _pending_proposal_block = NULL_BLOCK_ID; + + struct by_proposal_id{}; + struct by_proposal_height{}; + + typedef multi_index_container< + hs_proposal_message, + indexed_by< + hashed_unique< + tag, + BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) + >, + ordered_unique< + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) + > + > + > proposal_store_type; + + proposal_store_type _proposal_store; + + + digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ + + digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); + digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); + + return h2; + + } + + std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ + + std::vector ret_arr; + + proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); + + b_2_itr = _proposal_store.get().find( proposal_id ); + if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); + if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); + + if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); + if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); + if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); + + return ret_arr; + + } + + name qc_chain::get_proposer(){ + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + return hbs->header.producer; + + } + + name qc_chain::get_leader(){ + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + return hbs->header.producer; + + } + + + std::vector qc_chain::get_finalizers(){ + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + return hbs->active_schedule.producers; + + } + + hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { + + hs_proposal_message b_new; + + b_new.block_id = block_id; + b_new.parent_id = _b_leaf; + b_new.phase_counter = phase_counter; + + b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + + if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ + + std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + if (chain_length>=2){ + + auto itr = current_qc_chain.begin(); + + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + + if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; + else { + + proposal_store_type::nth_index<0>::type::iterator p_itr; + + p_itr = _proposal_store.get().find( b1.parent_id ); + + b_new.final_on_qc = p_itr->final_on_qc; + + } + + } + + } + + b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); + + ilog("=== creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + ("block_num", b_new.block_num()) + ("phase_counter", b_new.phase_counter) + ("proposal_id", b_new.proposal_id) + ("parent_id", b_new.parent_id) + ("justify", b_new.justify.proposal_id)); + + return b_new; + + } + + void reset_qc(fc::sha256 proposal_id){ + + _current_qc.proposal_id = proposal_id; + _current_qc.quorum_met = false; + _current_qc.active_finalizers = {}; + _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); + + } + + hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { + + hs_new_block_message b; + + b.block_id = block_id; + b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + + return b; + } + + bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ +/* +std::exception_ptr eptr; +try{*/ + + if (finalizers.size() < _threshold){ + return false; + } + + fc::crypto::blslib::bls_public_key agg_key; + + for (int i = 0; i < finalizers.size(); i++) { + + //adding finalizer's key to the aggregate pub key + if (i==0) agg_key = _private_key.get_public_key(); + else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); + + } + + fc::crypto::blslib::bls_signature justification_agg_sig; + + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; + + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); + + return ok; + +/*} +catch (...){ + ilog("error during evaluate_quorum"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr);*/ + + } + + bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ + +/*std::exception_ptr eptr; +try{ +*/ + if (qc.quorum_met == true ) { + return true; //skip evaluation if we've already verified quorum was met + } + else { + + //ilog("qc : ${qc}", ("qc", qc)); + + bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); + + qc.quorum_met = quorum_met; + + return qc.quorum_met ; + + } +/*} +catch (...){ + ilog("error during find proposals"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr);*/ + } + + void qc_chain::init(chain_plugin& chain_plug, std::set my_producers){ + + _chain_plug = &chain_plug; + _my_producers = my_producers; + + //ilog("qc chain initialized -> my producers : "); + + + } + + block_header_state_ptr qc_chain::get_block_header( const block_id_type& id ){ + + //ilog("get_block_header "); + + chain::controller& chain = _chain_plug->chain(); + + return chain.fork_db().get_block_header(id); + + } + + bool qc_chain::am_i_proposer(){ + + name proposer = get_proposer(); + + //ilog("Proposer : ${proposer}", ("proposer", proposer)); + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); + + if (prod_itr==_my_producers.end()) return false; + else return true; + + } + + bool qc_chain::am_i_leader(){ + + name leader = get_leader(); + + //ilog("Leader : ${leader}", ("leader", leader)); + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); + + if (prod_itr==_my_producers.end()) return false; + else return true; + + } + + bool qc_chain::am_i_finalizer(){ + + //ilog("am_i_finalizer"); + + std::vector finalizers = get_finalizers(); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); + + if (prod_itr!=finalizers.end()) return true; + + mf_itr++; + + } + + return false; + + } + + void qc_chain::process_proposal(hs_proposal_message proposal){ + + + auto itr = _proposal_store.get().find( proposal.proposal_id ); + + if (itr != _proposal_store.get().end()) { + ilog("*** proposal received twice : ${proposal_id}",("proposal_id", proposal.proposal_id)); + return ; //already aware of proposal, nothing to do + + } + + ilog("=== received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id) + ("parent_id", proposal.parent_id) + ("justify", proposal.justify.proposal_id)); + + _proposal_store.insert(proposal); //new proposal + + bool am_finalizer = am_i_finalizer(); + bool node_safe = is_node_safe(proposal); + + bool signature_required = am_finalizer && node_safe; + + //if I am a finalizer for this proposal, test safenode predicate for possible vote + if (signature_required){ + + //ilog("signature required"); + + _v_height = proposal.get_height(); + + fc::crypto::blslib::bls_signature agg_sig; + + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; + + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + //iterate over all my finalizers and sign / broadcast for each that is in the schedule + std::vector finalizers = get_finalizers(); + + //ilog("signed proposal. Broadcasting for each of my producers"); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); + + if (prod_itr!=finalizers.end()) { + + fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer + + hs_vote_message v_msg = {proposal.proposal_id, prod_itr->producer_name, sig}; + + broadcast_hs_vote(v_msg); + + }; + + mf_itr++; + + } + + } + + //update internal state + update(proposal); + + //check for leader change + on_leader_rotate(); + + } + + void qc_chain::process_vote(hs_vote_message vote){ + + //check for duplicate or invalid vote, return in either case + //abstracted [...] + + bool am_leader = am_i_leader(); //am I leader? + + if(!am_leader) return; + + //ilog("=== Process vote from ${finalizer}", ("finalizer", vote.finalizer)); + + //only leader need to take action on votes + + if (vote.proposal_id != _current_qc.proposal_id) return; + + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); + + if (p_itr==_proposal_store.get().end()){ + ilog("*** couldn't find proposal"); + + ilog("*** vote : ${vote}", ("vote", vote)); + + return; + } + + bool quorum_met = _current_qc.quorum_met; //check if quorum already met + + if (!quorum_met){ + + _current_qc.active_finalizers.push_back(vote.finalizer); + + if (_current_qc.active_finalizers.size()>1) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); + else _current_qc.active_agg_sig = vote.sig; + + quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); + + if (quorum_met){ + + _current_qc.quorum_met = true; + + //ilog("=== Quorum met on #${block_num} ${proposal_id} ", ("block_num", p_itr->block_num())("proposal_id", vote.proposal_id)); + + ilog("=== update_high_qc : _current_qc ==="); + update_high_qc(_current_qc); + + //check for leader change + on_leader_rotate(); + + + //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet + if (_chained_mode==false && p_itr->phase_counter<3){ + + hs_proposal_message proposal_candidate; + + if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); + else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); + + reset_qc(proposal_candidate.proposal_id); + + _pending_proposal_block = NULL_BLOCK_ID; + + broadcast_hs_proposal(proposal_candidate); + + _b_leaf = proposal_candidate.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + + } + + } + + } + + } + + void qc_chain::process_new_view(hs_new_view_message new_view){ + + ilog("=== update_high_qc : process_new_view === ${qc}", ("qc", new_view.high_qc)); + update_high_qc(new_view.high_qc); + + } + + void qc_chain::process_new_block(hs_new_block_message msg){ + + //ilog("=== Process new block ==="); + + } + + void qc_chain::broadcast_hs_proposal(hs_proposal_message msg){ + + //ilog("=== broadcast_hs_proposal ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_proposal_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_proposal_msg(ptr); + + process_proposal(msg); + + } + + + void qc_chain::broadcast_hs_vote(hs_vote_message msg){ + + //ilog("=== broadcast_hs_vote ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_vote_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_vote_msg(ptr); + + process_vote(msg); + + } + + void qc_chain::broadcast_hs_new_view(hs_new_view_message msg){ + + //ilog("=== broadcast_hs_new_view ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_new_view_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_new_view_msg(ptr); + + //process_new_view(msg); //notify ourselves + + } + + void qc_chain::broadcast_hs_new_block(hs_new_block_message msg){ + + //ilog("=== broadcast_hs_new_block ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_new_block_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_new_block_msg(ptr); + + //process_new_block(msg); //notify ourselves + + } + + //extends predicate + bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ + + + //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified + + + proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); + + uint32_t counter = 0; + + while (itr!=_proposal_store.get().end()){ + + itr = _proposal_store.get().find(itr->parent_id ); + + if (itr->proposal_id == ancestor){ + if (counter>25) { + ilog("***"); + ilog("*** took ${counter} iterations to find ancestor ", ("counter", counter)); + ilog("***"); + + } + return true; + } + + counter++; + + } + + ilog(" ***** extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", + ("d_proposal_id", descendant) + ("a_proposal_id", ancestor)); + + return false; + + } + + void qc_chain::on_beat(block_state& hbs){ +std::exception_ptr eptr; +try{ + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + ilog("=== on beat ==="); + + if (hbs.header.producer == "eosio"_n) return ; //if chain has not been activated and doesn't have finalizers, we don't generate proposals + + bool am_proposer = am_i_proposer(); + bool am_leader = am_i_leader(); + + //ilog("=== am_proposer = ${am_proposer}", ("am_proposer", am_proposer)); + //ilog("=== am_leader = ${am_leader}", ("am_leader", am_leader)); + + if (!am_proposer && !am_leader){ + + return; //nothing to do + + } + + //if I am the leader + if (am_leader){ + + //if I'm not also the proposer, perform block validation as required + if (!am_proposer){ + + //todo : extra validation + + } + + + if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ + + _pending_proposal_block = hbs.header.calculate_id(); + + } + else { + + hs_proposal_message proposal_candidate = new_proposal_candidate(hbs.header.calculate_id(), 0 ); + + reset_qc(proposal_candidate.proposal_id); + + _pending_proposal_block = NULL_BLOCK_ID; + + broadcast_hs_proposal(proposal_candidate); + + _b_leaf = proposal_candidate.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + + } + + } + else { + + //if I'm only a proposer and not the leader, I send a new block message + + hs_new_block_message block_candidate = new_block_candidate(hbs.header.calculate_id()); + + //ilog("=== broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); + + broadcast_hs_new_block(block_candidate); + + } + + //ilog(" === end of on_beat"); +} +catch (...){ + ilog("error during on_beat"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ + + ilog("=== check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); + + // if new high QC is higher than current, update to new + + + if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ + + _high_qc = high_qc; + _b_leaf = _high_qc.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + + } + else { + + proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; + proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; + + old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); + new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); + + if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); + if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); + + + if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ + + bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); + + if (quorum_met){ + + high_qc.quorum_met = true; + + //ilog("=== updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); + + _high_qc = high_qc; + _b_leaf = _high_qc.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + + } + + } + + } + + } + + void qc_chain::on_leader_rotate(){ + + ilog("on_leader_rotate"); + + chain::controller& chain = _chain_plug->chain(); + + //verify if leader changed + signed_block_header current_block_header = chain.head_block_state()->header; + + block_timestamp_type next_block_time = current_block_header.timestamp.next(); + + //ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", + // ("old_timestamp", current_block_header.timestamp)("new_timestamp", current_block_header.timestamp.next())); + + producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); + + if (current_block_header.producer != p_auth.producer_name){ + + ilog("/// rotating leader : ${old_leader} -> ${new_leader} ", + ("old_leader", current_block_header.producer)("new_leader", p_auth.producer_name)); + + //leader changed, we send our new_view message + + reset_qc(NULL_PROPOSAL_ID); + + _pending_proposal_block = NULL_BLOCK_ID; + + hs_new_view_message new_view; + + new_view.high_qc = _high_qc; + + broadcast_hs_new_view(new_view); + } + + + } + + //safenode predicate + bool qc_chain::is_node_safe(hs_proposal_message proposal){ + + //ilog("=== is_node_safe ==="); + + bool monotony_check = false; + bool safety_check = false; + bool liveness_check = false; + bool final_on_qc_check = false; + + fc::sha256 upcoming_commit; + + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated + else { + + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + if (chain_length>=2){ + + auto itr = current_qc_chain.begin(); + + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + + if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; + else { + + proposal_store_type::nth_index<0>::type::iterator p_itr; + + p_itr = _proposal_store.get().find( b1.parent_id ); + + upcoming_commit = p_itr->final_on_qc; + + } + + } + + //abstracted [...] + if (upcoming_commit == proposal.final_on_qc){ + final_on_qc_check = true; + } + + } + + if (proposal.get_height() > _v_height){ + monotony_check = true; + } + + if (_b_lock != NULL_PROPOSAL_ID){ + + //Safety check : check if this proposal extends the chain I'm locked on + if (extends(proposal.proposal_id, _b_lock)){ + safety_check = true; + } + + //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated + else { + + proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); + proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); + + if (prop_justification->get_height() > b_lock->get_height()){ + liveness_check = true; + } + } + + } + else { + + ilog("not locked on anything, liveness and safety are true"); + + //if we're not locked on anything, means the protocol just activated or chain just launched + liveness_check = true; + safety_check = true; + } + +/* ilog("=== final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", + ("final_on_qc_check", final_on_qc_check) + ("monotony_check", monotony_check) + ("liveness_check", liveness_check) + ("safety_check", safety_check));*/ + + return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully + + } + + //on proposal received, called from network thread + void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== on_hs_proposal_msg ==="); + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_proposal_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_proposal(msg); + + //ilog(" === end of on_hs_proposal_msg"); +} +catch (...){ + ilog("error during on_hs_proposal_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + //on vote received, called from network thread + void qc_chain::on_hs_vote_msg(hs_vote_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== on_hs_vote_msg ==="); + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_vote_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_vote(msg); + + //ilog(" === end of on_hs_vote_msg"); + } +catch (...){ + ilog("error during on_hs_vote_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + //on new view received, called from network thread + void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== on_hs_new_view_msg ==="); + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_new_view_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_new_view(msg); + + //ilog(" === end of on_hs_new_view_msg"); +} +catch (...){ + ilog("error during on_hs_new_view_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + //on new block received, called from network thread + void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== on_hs_new_block_msg ==="); + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_new_block_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_new_block(msg); + + //ilog(" === end of on_hs_new_block_msg"); +} +catch (...){ + ilog("error during on_hs_new_block_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + void qc_chain::update(hs_proposal_message proposal){ + + //ilog("=== update internal state ==="); + + chain::controller& chain = _chain_plug->chain(); + + proposal_store_type::nth_index<0>::type::iterator b_lock; + + //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ + ilog("*** proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)); + return; + } + + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + b_lock = _proposal_store.get().find( _b_lock); + + ilog("=== update_high_qc : proposal.justify ==="); + update_high_qc(proposal.justify); + + if (chain_length<1){ + ilog("*** qc chain length is 0"); + return; + } + + auto itr = current_qc_chain.begin(); + hs_proposal_message b_2 = *itr; + + if (chain_length<2){ + ilog("*** qc chain length is 1"); + return; + } + + itr++; + + hs_proposal_message b_1 = *itr; + + //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock + if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ + + //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); + _b_lock = b_1.proposal_id; //commit phase on b1 + + ilog("=== _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)); + + } + + if (chain_length<3){ + ilog("*** qc chain length is 2"); + return; + } + + itr++; + + hs_proposal_message b = *itr; + +/* ilog("direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", + ("b_2.parent_id",b_2.parent_id) + ("b_1.proposal_id", b_1.proposal_id) + ("b_1.parent_id", b_1.parent_id) + ("b.proposal_id", b.proposal_id));*/ + + //direct parent relationship verification + if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ + + //ilog("direct parent relationship verified"); + + + commit(b); + + //ilog("last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); + + //ilog("setting _b_exec to ${proposal_id}", ("proposal_id",b.proposal_id )); + _b_exec = b.proposal_id; //decide phase on b + _block_exec = b.block_id; + + clear_old_data( b.get_height()-1); //todo : figure out what number is actually needed + + //ilog("completed commit"); + + } + else { + + ilog("*** could not verify direct parent relationship"); + + ilog("*** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); + ilog("*** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); + ilog("*** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); + + } + + + } + + void qc_chain::clear_old_data(uint64_t cutoff){ + + //std::lock_guard g1( this->_proposal_store_mutex ); + //std::lock_guard g2( this-> _qc_store_mutex ); + + //ilog("clearing old data"); + + auto end_itr = _proposal_store.get().upper_bound(cutoff); + + while (_proposal_store.get().begin() != end_itr){ + + auto itr = _proposal_store.get().begin(); + + ilog("erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + ("block_num", itr->block_num()) + ("phase_counter", itr->phase_counter) + ("block_id", itr->block_id) + ("proposal_id", itr->proposal_id)); + + //auto qc_itr = _qc_store.get().find(itr->proposal_id); + + //if (qc_itr!=_qc_store.get().end()) _qc_store.get().erase(qc_itr); + _proposal_store.get().erase(itr); + + + } + + } + + void qc_chain::commit(hs_proposal_message proposal){ + +/* ilog("=== attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", proposal.block_num()) + ("proposal_id", proposal.proposal_id) + ("block_id", proposal.block_id) + ("phase_counter", proposal.phase_counter) + ("parent_id", proposal.parent_id)); + */ + bool sequence_respected = false; + + proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); + +/* ilog("=== _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", last_exec_prop->block_num()) + ("proposal_id", last_exec_prop->proposal_id) + ("block_id", last_exec_prop->block_id) + ("phase_counter", last_exec_prop->phase_counter) + ("parent_id", last_exec_prop->parent_id));*/ + + if (_b_exec==NULL_PROPOSAL_ID){ + //ilog("first block committed"); + sequence_respected = true; + } + else sequence_respected = last_exec_prop->get_height() < proposal.get_height(); + + if (sequence_respected){ + + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); + + if (p_itr != _proposal_store.get().end()){ + + //ilog("=== recursively committing" ); + + commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first + + } + + ilog("=== committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("block_id", proposal.block_id) + ("proposal_id", proposal.proposal_id)); + + } + + } + +}} + + diff --git a/plugins/producer_plugin/qc_chain.old2.cpp b/plugins/producer_plugin/qc_chain.old2.cpp new file mode 100644 index 0000000000..093174fc82 --- /dev/null +++ b/plugins/producer_plugin/qc_chain.old2.cpp @@ -0,0 +1,1216 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include + +#include + +//todo list / notes : + +/* + + + +fork tests in unittests + + + +network plugin versioning + +handshake_message.network_version + +independant of protocol feature activation + + + +separate library for hotstuff (look at SHIP libray used by state history plugin ) + + +boost tests producer plugin test + + + +regression tests python framework as a base + + + +performance testing + + + + +*/ + + + +// +// complete proposer / leader differentiation +// integration with new bls implementation +// +// hotstuff as a library with its own tests (model on state history plugin + state_history library ) +// +// unit / integration tests -> producer_plugin + fork_tests tests as a model +// +// test deterministic sequence +// +// test non-replica participation +// test finality vioaltion +// test loss of liveness +// +// test split chain +// +// integration with fork_db / LIB overhaul +// +// integration with performance testing +// +// regression testing ci/cd -> python regression tests +// +// add APIs for proof data +// +// add election proposal in block header +// +// map proposers / finalizers / leader to new host functions +// +// support pause / resume producer +// +// keep track of proposals sent to peers +// +// allow syncing of proposals +// +// versioning of net protocol version +// +// protocol feature activation HOTSTUFF_CONSENSUS +// +// system contract update 1 -> allow BPs to register + prove their aggregate pub key. Allow existing BPs to unreg + reg without new aggregate key. Prevent new BPs from registering without proving aggregate pub key +// +// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available +// +// + + +namespace eosio { namespace chain { + using boost::multi_index_container; + using namespace boost::multi_index; + + //todo : remove. bls12-381 key used for testing purposes + std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; + + fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); + + enum msg_type { + new_view = 1, + new_block = 2, + qc = 3, + vote = 4 + }; + + uint32_t _v_height; + + bool _chained_mode = false ; + + void handle_eptr(std::exception_ptr eptr){ + try { + if (eptr) { + std::rethrow_exception(eptr); + } + } catch(const std::exception& e) { + ilog("Caught exception ${ex}" , ("ex", e.what())); + std::exit(0); + } + } + + const block_id_type NULL_BLOCK_ID = block_id_type("00"); + const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); + +/* const block_header_state_ptr NULL_BLOCK_HEADER_STATE_PTR = block_header_state_ptr(); + const block_state_ptr NULL_BLOCK_STATE_PTR = block_state_ptr();*/ + + fc::sha256 _b_leaf = NULL_PROPOSAL_ID; + fc::sha256 _b_lock = NULL_PROPOSAL_ID; + fc::sha256 _b_exec = NULL_PROPOSAL_ID; + + block_id_type _block_exec = NULL_BLOCK_ID; + + eosio::chain::quorum_certificate _high_qc; + eosio::chain::quorum_certificate _current_qc; + + eosio::chain::extended_schedule _schedule; + + chain_plugin* _chain_plug = nullptr; + std::set _my_producers; + + block_id_type _pending_proposal_block = NULL_BLOCK_ID; + + struct by_proposal_id{}; + struct by_proposal_height{}; + + typedef multi_index_container< + hs_proposal_message, + indexed_by< + hashed_unique< + tag, + BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) + >, + ordered_unique< + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) + > + > + > proposal_store_type; + + proposal_store_type _proposal_store; + + + digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ + + digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); + digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); + + return h2; + + } + + std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ + + std::vector ret_arr; + + proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); + + b_2_itr = _proposal_store.get().find( proposal_id ); + if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); + if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); + + if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); + if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); + if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); + + return ret_arr; + + } + + name qc_chain::get_proposer(){ + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + return hbs->header.producer; + + } + + name qc_chain::get_leader(){ + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + return hbs->header.producer; + + } + + + std::vector qc_chain::get_finalizers(){ + + chain::controller& chain = _chain_plug->chain(); + + const auto& hbs = chain.head_block_state(); + + return hbs->active_schedule.producers; + + } + + hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { + + hs_proposal_message b_new; + + b_new.block_id = block_id; + b_new.parent_id = _b_leaf; + b_new.phase_counter = phase_counter; + + b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + + if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ + + std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + if (chain_length>=2){ + + auto itr = current_qc_chain.begin(); + + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + + if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; + else { + + proposal_store_type::nth_index<0>::type::iterator p_itr; + + p_itr = _proposal_store.get().find( b1.parent_id ); + + b_new.final_on_qc = p_itr->final_on_qc; + + } + + } + + } + + b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); + + ilog("=== creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + ("block_num", b_new.block_num()) + ("phase_counter", b_new.phase_counter) + ("proposal_id", b_new.proposal_id) + ("parent_id", b_new.parent_id) + ("justify", b_new.justify.proposal_id)); + + return b_new; + + } + + void reset_qc(fc::sha256 proposal_id){ + + _current_qc.proposal_id = proposal_id; + _current_qc.quorum_met = false; + _current_qc.active_finalizers = {}; + _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); + + } + + hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { + + hs_new_block_message b; + + b.block_id = block_id; + b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + + return b; + } + + bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ +/* +std::exception_ptr eptr; +try{*/ + + if (finalizers.size() < _threshold){ + return false; + } + + fc::crypto::blslib::bls_public_key agg_key; + + for (int i = 0; i < finalizers.size(); i++) { + + //adding finalizer's key to the aggregate pub key + if (i==0) agg_key = _private_key.get_public_key(); + else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); + + } + + fc::crypto::blslib::bls_signature justification_agg_sig; + + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; + + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); + + return ok; + +/*} +catch (...){ + ilog("error during evaluate_quorum"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr);*/ + + } + + bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ + +/*std::exception_ptr eptr; +try{ +*/ + if (qc.quorum_met == true ) { + return true; //skip evaluation if we've already verified quorum was met + } + else { + + //ilog("qc : ${qc}", ("qc", qc)); + + bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); + + qc.quorum_met = quorum_met; + + return qc.quorum_met ; + + } +/*} +catch (...){ + ilog("error during find proposals"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr);*/ + } + + void qc_chain::init(chain_plugin& chain_plug, std::set my_producers){ + + _chain_plug = &chain_plug; + _my_producers = my_producers; + + //ilog("qc chain initialized -> my producers : "); + + + } + + block_header_state_ptr qc_chain::get_block_header( const block_id_type& id ){ + + //ilog("get_block_header "); + + chain::controller& chain = _chain_plug->chain(); + + return chain.fork_db().get_block_header(id); + + } + + bool qc_chain::am_i_proposer(){ + + name proposer = get_proposer(); + + //ilog("Proposer : ${proposer}", ("proposer", proposer)); + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); + + if (prod_itr==_my_producers.end()) return false; + else return true; + + } + + bool qc_chain::am_i_leader(){ + + name leader = get_leader(); + + //ilog("Leader : ${leader}", ("leader", leader)); + + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); + + if (prod_itr==_my_producers.end()) return false; + else return true; + + } + + bool qc_chain::am_i_finalizer(){ + + //ilog("am_i_finalizer"); + + std::vector finalizers = get_finalizers(); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); + + if (prod_itr!=finalizers.end()) return true; + + mf_itr++; + + } + + return false; + + } + + void qc_chain::process_proposal(hs_proposal_message proposal){ + + + auto itr = _proposal_store.get().find( proposal.proposal_id ); + + if (itr != _proposal_store.get().end()) { + ilog("*** proposal received twice : ${proposal_id}",("proposal_id", proposal.proposal_id)); + return ; //already aware of proposal, nothing to do + + } + + ilog("=== received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id) + ("parent_id", proposal.parent_id) + ("justify", proposal.justify.proposal_id)); + + _proposal_store.insert(proposal); //new proposal + + bool am_finalizer = am_i_finalizer(); + bool node_safe = is_node_safe(proposal); + + bool signature_required = am_finalizer && node_safe; + + //if I am a finalizer for this proposal, test safenode predicate for possible vote + if (signature_required){ + + //ilog("signature required"); + + _v_height = proposal.get_height(); + + fc::crypto::blslib::bls_signature agg_sig; + + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; + + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + //iterate over all my finalizers and sign / broadcast for each that is in the schedule + std::vector finalizers = get_finalizers(); + + //ilog("signed proposal. Broadcasting for each of my producers"); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); + + if (prod_itr!=finalizers.end()) { + + fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer + + hs_vote_message v_msg = {proposal.proposal_id, prod_itr->producer_name, sig}; + + broadcast_hs_vote(v_msg); + + }; + + mf_itr++; + + } + + } + + //update internal state + update(proposal); + + //check for leader change + on_leader_rotate(); + + } + + void qc_chain::process_vote(hs_vote_message vote){ + + //check for duplicate or invalid vote, return in either case + //abstracted [...] + + bool am_leader = am_i_leader(); //am I leader? + + if(!am_leader) return; + + //ilog("=== Process vote from ${finalizer}", ("finalizer", vote.finalizer)); + + //only leader need to take action on votes + + if (vote.proposal_id != _current_qc.proposal_id) return; + + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); + + if (p_itr==_proposal_store.get().end()){ + ilog("*** couldn't find proposal"); + + ilog("*** vote : ${vote}", ("vote", vote)); + + return; + } + + bool quorum_met = _current_qc.quorum_met; //check if quorum already met + + if (!quorum_met){ + + _current_qc.active_finalizers.push_back(vote.finalizer); + + if (_current_qc.active_finalizers.size()>1) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); + else _current_qc.active_agg_sig = vote.sig; + + quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); + + if (quorum_met){ + + _current_qc.quorum_met = true; + + //ilog("=== Quorum met on #${block_num} ${proposal_id} ", ("block_num", p_itr->block_num())("proposal_id", vote.proposal_id)); + + ilog("=== update_high_qc : _current_qc ==="); + update_high_qc(_current_qc); + + //check for leader change + on_leader_rotate(); + + + //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet + if (_chained_mode==false && p_itr->phase_counter<3){ + + hs_proposal_message proposal_candidate; + + if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); + else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); + + reset_qc(proposal_candidate.proposal_id); + + _pending_proposal_block = NULL_BLOCK_ID; + + broadcast_hs_proposal(proposal_candidate); + + _b_leaf = proposal_candidate.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + + } + + } + + } + + } + + void qc_chain::process_new_view(hs_new_view_message new_view){ + + ilog("=== update_high_qc : process_new_view === ${qc}", ("qc", new_view.high_qc)); + update_high_qc(new_view.high_qc); + + } + + void qc_chain::process_new_block(hs_new_block_message msg){ + + //ilog("=== Process new block ==="); + + } + + void qc_chain::broadcast_hs_proposal(hs_proposal_message msg){ + + //ilog("=== broadcast_hs_proposal ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_proposal_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_proposal_msg(ptr); + + process_proposal(msg); + + } + + + void qc_chain::broadcast_hs_vote(hs_vote_message msg){ + + //ilog("=== broadcast_hs_vote ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_vote_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_vote_msg(ptr); + + process_vote(msg); + + } + + void qc_chain::broadcast_hs_new_view(hs_new_view_message msg){ + + //ilog("=== broadcast_hs_new_view ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_new_view_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_new_view_msg(ptr); + + //process_new_view(msg); //notify ourselves + + } + + void qc_chain::broadcast_hs_new_block(hs_new_block_message msg){ + + //ilog("=== broadcast_hs_new_block ==="); + + chain::controller& chain = _chain_plug->chain(); + + hs_new_block_message_ptr ptr = std::make_shared(msg); + + chain.commit_hs_new_block_msg(ptr); + + //process_new_block(msg); //notify ourselves + + } + + //extends predicate + bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ + + + //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified + + + proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); + + uint32_t counter = 0; + + while (itr!=_proposal_store.get().end()){ + + itr = _proposal_store.get().find(itr->parent_id ); + + if (itr->proposal_id == ancestor){ + if (counter>25) { + ilog("***"); + ilog("*** took ${counter} iterations to find ancestor ", ("counter", counter)); + ilog("***"); + + } + return true; + } + + counter++; + + } + + ilog(" ***** extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", + ("d_proposal_id", descendant) + ("a_proposal_id", ancestor)); + + return false; + + } + + void qc_chain::on_beat(block_state& hbs){ +std::exception_ptr eptr; +try{ + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + ilog("=== on beat ==="); + + if (hbs.header.producer == "eosio"_n) return ; //if chain has not been activated and doesn't have finalizers, we don't generate proposals + + bool am_proposer = am_i_proposer(); + bool am_leader = am_i_leader(); + + //ilog("=== am_proposer = ${am_proposer}", ("am_proposer", am_proposer)); + //ilog("=== am_leader = ${am_leader}", ("am_leader", am_leader)); + + if (!am_proposer && !am_leader){ + + return; //nothing to do + + } + + //if I am the leader + if (am_leader){ + + //if I'm not also the proposer, perform block validation as required + if (!am_proposer){ + + //todo : extra validation + + } + + + if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ + + _pending_proposal_block = hbs.header.calculate_id(); + + } + else { + + hs_proposal_message proposal_candidate = new_proposal_candidate(hbs.header.calculate_id(), 0 ); + + reset_qc(proposal_candidate.proposal_id); + + _pending_proposal_block = NULL_BLOCK_ID; + + broadcast_hs_proposal(proposal_candidate); + + _b_leaf = proposal_candidate.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + + } + + } + else { + + //if I'm only a proposer and not the leader, I send a new block message + + hs_new_block_message block_candidate = new_block_candidate(hbs.header.calculate_id()); + + //ilog("=== broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); + + broadcast_hs_new_block(block_candidate); + + } + + //ilog(" === end of on_beat"); +} +catch (...){ + ilog("error during on_beat"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ + + ilog("=== check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); + + // if new high QC is higher than current, update to new + + + if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ + + _high_qc = high_qc; + _b_leaf = _high_qc.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + + } + else { + + proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; + proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; + + old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); + new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); + + if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); + if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); + + + if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ + + bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); + + if (quorum_met){ + + high_qc.quorum_met = true; + + //ilog("=== updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); + + _high_qc = high_qc; + _b_leaf = _high_qc.proposal_id; + + ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + + } + + } + + } + + } + + void qc_chain::on_leader_rotate(){ + + ilog("on_leader_rotate"); + + chain::controller& chain = _chain_plug->chain(); + + //verify if leader changed + signed_block_header current_block_header = chain.head_block_state()->header; + + block_timestamp_type next_block_time = current_block_header.timestamp.next(); + + //ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", + // ("old_timestamp", current_block_header.timestamp)("new_timestamp", current_block_header.timestamp.next())); + + producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); + + if (current_block_header.producer != p_auth.producer_name){ + + ilog("/// rotating leader : ${old_leader} -> ${new_leader} ", + ("old_leader", current_block_header.producer)("new_leader", p_auth.producer_name)); + + //leader changed, we send our new_view message + + reset_qc(NULL_PROPOSAL_ID); + + _pending_proposal_block = NULL_BLOCK_ID; + + hs_new_view_message new_view; + + new_view.high_qc = _high_qc; + + broadcast_hs_new_view(new_view); + } + + + } + + //safenode predicate + bool qc_chain::is_node_safe(hs_proposal_message proposal){ + + //ilog("=== is_node_safe ==="); + + bool monotony_check = false; + bool safety_check = false; + bool liveness_check = false; + bool final_on_qc_check = false; + + fc::sha256 upcoming_commit; + + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated + else { + + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + if (chain_length>=2){ + + auto itr = current_qc_chain.begin(); + + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + + if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; + else { + + proposal_store_type::nth_index<0>::type::iterator p_itr; + + p_itr = _proposal_store.get().find( b1.parent_id ); + + upcoming_commit = p_itr->final_on_qc; + + } + + } + + //abstracted [...] + if (upcoming_commit == proposal.final_on_qc){ + final_on_qc_check = true; + } + + } + + if (proposal.get_height() > _v_height){ + monotony_check = true; + } + + if (_b_lock != NULL_PROPOSAL_ID){ + + //Safety check : check if this proposal extends the chain I'm locked on + if (extends(proposal.proposal_id, _b_lock)){ + safety_check = true; + } + + //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated + else { + + proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); + proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); + + if (prop_justification->get_height() > b_lock->get_height()){ + liveness_check = true; + } + } + + } + else { + + ilog("not locked on anything, liveness and safety are true"); + + //if we're not locked on anything, means the protocol just activated or chain just launched + liveness_check = true; + safety_check = true; + } + +/* ilog("=== final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", + ("final_on_qc_check", final_on_qc_check) + ("monotony_check", monotony_check) + ("liveness_check", liveness_check) + ("safety_check", safety_check));*/ + + return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully + + } + + //on proposal received, called from network thread + void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== on_hs_proposal_msg ==="); + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_proposal_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_proposal(msg); + + //ilog(" === end of on_hs_proposal_msg"); +} +catch (...){ + ilog("error during on_hs_proposal_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + //on vote received, called from network thread + void qc_chain::on_hs_vote_msg(hs_vote_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== on_hs_vote_msg ==="); + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_vote_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_vote(msg); + + //ilog(" === end of on_hs_vote_msg"); + } +catch (...){ + ilog("error during on_hs_vote_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + //on new view received, called from network thread + void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== on_hs_new_view_msg ==="); + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_new_view_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_new_view(msg); + + //ilog(" === end of on_hs_new_view_msg"); +} +catch (...){ + ilog("error during on_hs_new_view_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + //on new block received, called from network thread + void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ +std::exception_ptr eptr; +try{ + + //ilog("=== on_hs_new_block_msg ==="); + + std::lock_guard g( this-> _hotstuff_state_mutex ); + + //std::lock_guard g( this->_new_block_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + + process_new_block(msg); + + //ilog(" === end of on_hs_new_block_msg"); +} +catch (...){ + ilog("error during on_hs_new_block_msg"); + eptr = std::current_exception(); // capture +} +handle_eptr(eptr); + } + + void qc_chain::update(hs_proposal_message proposal){ + + //ilog("=== update internal state ==="); + + chain::controller& chain = _chain_plug->chain(); + + proposal_store_type::nth_index<0>::type::iterator b_lock; + + //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ + ilog("*** proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)); + return; + } + + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + b_lock = _proposal_store.get().find( _b_lock); + + ilog("=== update_high_qc : proposal.justify ==="); + update_high_qc(proposal.justify); + + if (chain_length<1){ + ilog("*** qc chain length is 0"); + return; + } + + auto itr = current_qc_chain.begin(); + hs_proposal_message b_2 = *itr; + + if (chain_length<2){ + ilog("*** qc chain length is 1"); + return; + } + + itr++; + + hs_proposal_message b_1 = *itr; + + //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock + if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ + + //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); + _b_lock = b_1.proposal_id; //commit phase on b1 + + ilog("=== _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)); + + } + + if (chain_length<3){ + ilog("*** qc chain length is 2"); + return; + } + + itr++; + + hs_proposal_message b = *itr; + +/* ilog("direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", + ("b_2.parent_id",b_2.parent_id) + ("b_1.proposal_id", b_1.proposal_id) + ("b_1.parent_id", b_1.parent_id) + ("b.proposal_id", b.proposal_id));*/ + + //direct parent relationship verification + if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ + + //ilog("direct parent relationship verified"); + + + commit(b); + + //ilog("last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); + + //ilog("setting _b_exec to ${proposal_id}", ("proposal_id",b.proposal_id )); + _b_exec = b.proposal_id; //decide phase on b + _block_exec = b.block_id; + + clear_old_data( b.get_height()-1); //todo : figure out what number is actually needed + + //ilog("completed commit"); + + } + else { + + ilog("*** could not verify direct parent relationship"); + + ilog("*** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); + ilog("*** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); + ilog("*** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); + + } + + + } + + void qc_chain::clear_old_data(uint64_t cutoff){ + + //std::lock_guard g1( this->_proposal_store_mutex ); + //std::lock_guard g2( this-> _qc_store_mutex ); + + //ilog("clearing old data"); + + auto end_itr = _proposal_store.get().upper_bound(cutoff); + + while (_proposal_store.get().begin() != end_itr){ + + auto itr = _proposal_store.get().begin(); + + ilog("erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + ("block_num", itr->block_num()) + ("phase_counter", itr->phase_counter) + ("block_id", itr->block_id) + ("proposal_id", itr->proposal_id)); + + //auto qc_itr = _qc_store.get().find(itr->proposal_id); + + //if (qc_itr!=_qc_store.get().end()) _qc_store.get().erase(qc_itr); + _proposal_store.get().erase(itr); + + + } + + } + + void qc_chain::commit(hs_proposal_message proposal){ + +/* ilog("=== attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", proposal.block_num()) + ("proposal_id", proposal.proposal_id) + ("block_id", proposal.block_id) + ("phase_counter", proposal.phase_counter) + ("parent_id", proposal.parent_id)); + */ + bool sequence_respected = false; + + proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); + +/* ilog("=== _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", last_exec_prop->block_num()) + ("proposal_id", last_exec_prop->proposal_id) + ("block_id", last_exec_prop->block_id) + ("phase_counter", last_exec_prop->phase_counter) + ("parent_id", last_exec_prop->parent_id));*/ + + if (_b_exec==NULL_PROPOSAL_ID){ + //ilog("first block committed"); + sequence_respected = true; + } + else sequence_respected = last_exec_prop->get_height() < proposal.get_height(); + + if (sequence_respected){ + + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); + + if (p_itr != _proposal_store.get().end()){ + + //ilog("=== recursively committing" ); + + commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first + + } + + ilog("=== committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("block_id", proposal.block_id) + ("proposal_id", proposal.proposal_id)); + + } + + } + +}} + + diff --git a/tests/hotstuff_tests.cpp b/tests/hotstuff_tests.cpp new file mode 100644 index 0000000000..e69de29bb2 From 8d38b091fe66f0e2ebe1166b2a66f763efcfd771 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 24 Mar 2023 11:02:04 +0000 Subject: [PATCH 013/151] Refactor to extract liveness component and work on unit tests --- .../chain/include/eosio/chain/config.hpp | 2 +- .../chain/include/eosio/chain/hotstuff.hpp | 22 +- libraries/hotstuff/chain_pacemaker.cpp | 18 +- .../include/eosio/hotstuff/base_pacemaker.hpp | 16 +- .../eosio/hotstuff/chain_pacemaker.hpp | 18 +- .../include/eosio/hotstuff/qc_chain.hpp | 90 ++-- .../include/eosio/hotstuff/test_pacemaker.hpp | 32 +- libraries/hotstuff/qc_chain.cpp | 229 +++++++-- libraries/hotstuff/test/test_hotstuff.cpp | 467 ++++++++++++++---- libraries/hotstuff/test_pacemaker.cpp | 52 +- plugins/producer_plugin/producer_plugin.cpp | 10 +- 11 files changed, 685 insertions(+), 271 deletions(-) diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 096bc69f88..5f1cbceb80 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -33,7 +33,7 @@ const static name owner_name { "owner"_n }; const static name eosio_any_name { "eosio.any"_n }; const static name eosio_code_name { "eosio.code"_n }; -const static int block_interval_ms = 500; +const static int block_interval_ms = 5000; const static int block_interval_us = block_interval_ms*1000; const static uint64_t block_timestamp_epoch = 946684800000ll; // epoch is year 2000. const static uint32_t genesis_num_supported_key_types = 2; diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index c1df5eb302..cba1c5ef48 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -9,6 +9,10 @@ namespace eosio { namespace chain { + + const block_id_type NULL_BLOCK_ID = block_id_type("00"); + const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); + //using namespace fc::crypto::blslib; //todo : fetch from chain / nodeos config @@ -39,7 +43,7 @@ namespace eosio { namespace chain { public: - fc::sha256 proposal_id; + fc::sha256 proposal_id = NULL_PROPOSAL_ID; bool quorum_met = false; @@ -50,7 +54,7 @@ namespace eosio { namespace chain { struct hs_vote_message { - fc::sha256 proposal_id; //vote on proposal + fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal name finalizer; fc::crypto::blslib::bls_signature sig; @@ -65,16 +69,16 @@ namespace eosio { namespace chain { struct hs_proposal_message { - fc::sha256 proposal_id; //vote on proposal + fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal - block_id_type block_id; - uint8_t phase_counter; + block_id_type block_id = NULL_BLOCK_ID; + uint8_t phase_counter = 0; - fc::sha256 parent_id; //new proposal + fc::sha256 parent_id = NULL_PROPOSAL_ID; //new proposal - fc::sha256 final_on_qc; + fc::sha256 final_on_qc = NULL_PROPOSAL_ID; - quorum_certificate justify; //justification + quorum_certificate justify; //justification hs_proposal_message() = default; @@ -90,7 +94,7 @@ namespace eosio { namespace chain { struct hs_new_block_message { - block_id_type block_id; //new proposal + block_id_type block_id = NULL_BLOCK_ID; //new proposal quorum_certificate justify; //justification diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 5ac85561aa..3fbbdad6e3 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -82,7 +82,7 @@ namespace eosio { namespace hotstuff { //delete _qc_chain; }; - void chain_pacemaker::send_hs_proposal_msg(hs_proposal_message msg){ + void chain_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ hs_proposal_message_ptr msg_ptr = std::make_shared(msg); @@ -90,7 +90,7 @@ namespace eosio { namespace hotstuff { }; - void chain_pacemaker::send_hs_vote_msg(hs_vote_message msg){ + void chain_pacemaker::send_hs_vote_msg(name id, hs_vote_message msg){ hs_vote_message_ptr msg_ptr = std::make_shared(msg); @@ -98,7 +98,7 @@ namespace eosio { namespace hotstuff { }; - void chain_pacemaker::send_hs_new_block_msg(hs_new_block_message msg){ + void chain_pacemaker::send_hs_new_block_msg(name id, hs_new_block_message msg){ hs_new_block_message_ptr msg_ptr = std::make_shared(msg); @@ -106,7 +106,7 @@ namespace eosio { namespace hotstuff { }; - void chain_pacemaker::send_hs_new_view_msg(hs_new_view_message msg){ + void chain_pacemaker::send_hs_new_view_msg(name id, hs_new_view_message msg){ hs_new_view_message_ptr msg_ptr = std::make_shared(msg); @@ -114,28 +114,28 @@ namespace eosio { namespace hotstuff { }; - void chain_pacemaker::on_hs_proposal_msg(hs_proposal_message msg){ + void chain_pacemaker::on_hs_proposal_msg(name id, hs_proposal_message msg){ - std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + std::lock_guard g( this-> _hotstuff_state_mutex ); _qc_chain->on_hs_proposal_msg(msg); } - void chain_pacemaker::on_hs_vote_msg(hs_vote_message msg){ + void chain_pacemaker::on_hs_vote_msg(name id, hs_vote_message msg){ std::lock_guard g( this-> _hotstuff_state_mutex ); _qc_chain->on_hs_vote_msg(msg); } - void chain_pacemaker::on_hs_new_block_msg(hs_new_block_message msg){ + void chain_pacemaker::on_hs_new_block_msg(name id, hs_new_block_message msg){ std::lock_guard g( this-> _hotstuff_state_mutex ); _qc_chain->on_hs_new_block_msg(msg); } - void chain_pacemaker::on_hs_new_view_msg(hs_new_view_message msg){ + void chain_pacemaker::on_hs_new_view_msg(name id, hs_new_view_message msg){ std::lock_guard g( this-> _hotstuff_state_mutex ); diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index 7dc2029d0d..eba0069195 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -53,16 +53,16 @@ namespace eosio { namespace hotstuff { //outbound communications - virtual void send_hs_proposal_msg(hs_proposal_message msg) = 0; - virtual void send_hs_vote_msg(hs_vote_message msg) = 0; - virtual void send_hs_new_block_msg(hs_new_block_message msg) = 0; - virtual void send_hs_new_view_msg(hs_new_view_message msg) = 0; + virtual void send_hs_proposal_msg(name id, hs_proposal_message msg) = 0; + virtual void send_hs_vote_msg(name id, hs_vote_message msg) = 0; + virtual void send_hs_new_block_msg(name id, hs_new_block_message msg) = 0; + virtual void send_hs_new_view_msg(name id, hs_new_view_message msg) = 0; //inbound communications - virtual void on_hs_vote_msg(hs_vote_message msg) = 0; //confirmation msg event handler - virtual void on_hs_proposal_msg(hs_proposal_message msg) = 0; //consensus msg event handler - virtual void on_hs_new_view_msg(hs_new_view_message msg) = 0; //new view msg event handler - virtual void on_hs_new_block_msg(hs_new_block_message msg) = 0; //new block msg event handler + virtual void on_hs_vote_msg(name id, hs_vote_message msg) = 0; //confirmation msg event handler + virtual void on_hs_proposal_msg(name id, hs_proposal_message msg) = 0; //consensus msg event handler + virtual void on_hs_new_view_msg(name id, hs_new_view_message msg) = 0; //new view msg event handler + virtual void on_hs_new_block_msg(name id, hs_new_block_message msg) = 0; //new block msg event handler }; diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index 6442c97885..90ee183ab7 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -32,15 +32,15 @@ namespace eosio { namespace hotstuff { void beat(); - void send_hs_proposal_msg(hs_proposal_message msg); - void send_hs_vote_msg(hs_vote_message msg); - void send_hs_new_block_msg(hs_new_block_message msg); - void send_hs_new_view_msg(hs_new_view_message msg); - - void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler - void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler - void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler + void send_hs_proposal_msg(name id, hs_proposal_message msg); + void send_hs_vote_msg(name id, hs_vote_message msg); + void send_hs_new_block_msg(name id, hs_new_block_message msg); + void send_hs_new_view_msg(name id, hs_new_view_message msg); + + void on_hs_vote_msg(name id, hs_vote_message msg); //confirmation msg event handler + void on_hs_proposal_msg(name id, hs_proposal_message msg); //consensus msg event handler + void on_hs_new_view_msg(name id, hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(name id, hs_new_block_message msg); //new block msg event handler private : diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 87e304fc61..b43034936c 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -44,7 +44,11 @@ namespace eosio { namespace hotstuff { } }; - qc_chain(){}; + qc_chain(){ + //ilog("_high_qc : ${qc_id}", ("qc_id", _high_qc.proposal_id)); + + }; + ~qc_chain(){ /* if (_pacemaker == NULL) delete _pacemaker; @@ -67,19 +71,21 @@ namespace eosio { namespace hotstuff { vote = 4 }; - uint32_t _v_height; bool _chained_mode = false ; - const block_id_type NULL_BLOCK_ID = block_id_type("00"); - const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - fc::sha256 _b_leaf = NULL_PROPOSAL_ID; fc::sha256 _b_lock = NULL_PROPOSAL_ID; fc::sha256 _b_exec = NULL_PROPOSAL_ID; block_id_type _block_exec = NULL_BLOCK_ID; + block_id_type _pending_proposal_block = NULL_BLOCK_ID; + + uint32_t _v_height; + + bool _log = true; + eosio::chain::quorum_certificate _high_qc; eosio::chain::quorum_certificate _current_qc; @@ -87,7 +93,7 @@ namespace eosio { namespace hotstuff { std::set _my_producers; - block_id_type _pending_proposal_block = NULL_BLOCK_ID; + name _id; struct by_proposal_id{}; struct by_proposal_height{}; @@ -106,70 +112,68 @@ namespace eosio { namespace hotstuff { > > proposal_store_type; - proposal_store_type _proposal_store; - - //uint32_t _threshold = 15; + proposal_store_type _proposal_store; //internal proposals store - digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc); + digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc); //get digest to sign from proposal data - void reset_qc(fc::sha256 proposal_id); + void reset_qc(fc::sha256 proposal_id); //reset current internal qc - bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal); + bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal); //evaluate quorum for a proposal - name get_proposer(); +/* name get_proposer(); name get_leader(); - name get_incoming_leader(); + name get_incoming_leader(); //get incoming leader*/ - bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); + bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); //check if quorum has been met over a proposal - std::vector get_finalizers(); + std::vector get_finalizers(); //get current finalizers set - hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); - hs_new_block_message new_block_candidate(block_id_type block_id); + hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); //create new proposal message + hs_new_block_message new_block_candidate(block_id_type block_id); //create new block message - void init(name id, base_pacemaker& pacemaker, std::set my_producers); + void init(name id, base_pacemaker& pacemaker, std::set my_producers, bool logging_enabled); //initialize qc object and add reference to the pacemaker - bool am_i_proposer(); - bool am_i_leader(); - bool am_i_finalizer(); + bool am_i_proposer(); //check if I am the current proposer + bool am_i_leader(); //check if I am the current leader + bool am_i_finalizer(); //check if I am one of the current finalizers - void process_proposal(hs_proposal_message msg); - void process_vote(hs_vote_message msg); - void process_new_view(hs_new_view_message msg); - void process_new_block(hs_new_block_message msg); + void process_proposal(hs_proposal_message msg); //handles proposal + void process_vote(hs_vote_message msg); //handles vote + void process_new_view(hs_new_view_message msg); //handles new view + void process_new_block(hs_new_block_message msg); //handles new block - bool extends(fc::sha256 descendant, fc::sha256 ancestor); + hs_vote_message sign_proposal(hs_proposal_message proposal, name finalizer); //sign proposal - void on_beat(); + bool extends(fc::sha256 descendant, fc::sha256 ancestor); //verify that a proposal descends from another - void update_high_qc(eosio::chain::quorum_certificate high_qc); + void on_beat(); //handler for pacemaker beat() - void on_leader_rotate(); + void update_high_qc(eosio::chain::quorum_certificate high_qc); //check if update to our high qc is required - bool is_node_safe(hs_proposal_message proposal); + void leader_rotation_check(); //check if leader rotation is required - std::vector get_qc_chain(fc::sha256 proposal_id); + bool is_node_safe(hs_proposal_message proposal); //verify if a proposal should be signed + + std::vector get_qc_chain(fc::sha256 proposal_id); //get 3-phase proposal justification - void send_hs_proposal_msg(hs_proposal_message msg); - void send_hs_vote_msg(hs_vote_message msg); - void send_hs_new_view_msg(hs_new_view_message msg); - void send_hs_new_block_msg(hs_new_block_message msg); + void send_hs_proposal_msg(hs_proposal_message msg); //send vote msg + void send_hs_vote_msg(hs_vote_message msg); //send proposal msg + void send_hs_new_view_msg(hs_new_view_message msg); //send new view msg + void send_hs_new_block_msg(hs_new_block_message msg); //send new block msg - void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler - void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler + void on_hs_vote_msg(hs_vote_message msg); //vote msg event handler + void on_hs_proposal_msg(hs_proposal_message msg); //proposal msg event handler void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler - void update(hs_proposal_message proposal); - void commit(hs_proposal_message proposal); + void update(hs_proposal_message proposal); //update internal state + void commit(hs_proposal_message proposal); //commit proposal (finality) - void gc_proposals(uint64_t cutoff); + void gc_proposals(uint64_t cutoff); //garbage collection of old proposals private : - name _id; - base_pacemaker* _pacemaker = NULL; }; diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index 9997302080..76acb8a95a 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -26,7 +26,7 @@ namespace eosio { namespace hotstuff { //if (_qc_chain == NULL) delete _qc_chain; - //_qc_chain = NULL; + _qc_chain = NULL; }; @@ -52,7 +52,7 @@ namespace eosio { namespace hotstuff { void send_hs_new_block_msg(hs_new_block_message msg); void send_hs_new_view_msg(hs_new_view_message msg);*/ - using hotstuff_message = std::variant; + using hotstuff_message = std::pair>; //void init(std::vector unique_replicas); @@ -68,11 +68,18 @@ namespace eosio { namespace hotstuff { void set_quorum_threshold(uint32_t threshold); + void add_message_to_queue(hotstuff_message msg); + void propagate(); //indexed_qc_chain get_qc_chain(name replica); - //~test_pacemaker(){}; + ~test_pacemaker(){ + + _qcc_store.get().clear(); + + }; + //base_pacemaker interface functions @@ -90,20 +97,21 @@ namespace eosio { namespace hotstuff { void beat(); - void send_hs_proposal_msg(hs_proposal_message msg); - void send_hs_vote_msg(hs_vote_message msg); - void send_hs_new_block_msg(hs_new_block_message msg); - void send_hs_new_view_msg(hs_new_view_message msg); + void send_hs_proposal_msg(name id, hs_proposal_message msg); + void send_hs_vote_msg(name id, hs_vote_message msg); + void send_hs_new_block_msg(name id, hs_new_block_message msg); + void send_hs_new_view_msg(name id, hs_new_view_message msg); + + void on_hs_vote_msg(name id, hs_vote_message msg); //confirmation msg event handler + void on_hs_proposal_msg(name id, hs_proposal_message msg); //consensus msg event handler + void on_hs_new_view_msg(name id, hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(name id, hs_new_block_message msg); //new block msg event handler - void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler - void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler - void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler + std::vector _pending_message_queue; private : std::vector _message_queue; - std::vector _pending_message_queue; name _proposer; name _leader; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 50d220a291..ead986948c 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -157,7 +157,8 @@ namespace eosio { namespace hotstuff { b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); - ilog("=== creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + if (_log) ilog("=== ${id} creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + ("id", _id) ("block_num", b_new.block_num()) ("phase_counter", b_new.phase_counter) ("proposal_id", b_new.proposal_id) @@ -170,6 +171,7 @@ namespace eosio { namespace hotstuff { void qc_chain::reset_qc(fc::sha256 proposal_id){ + if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); _current_qc.proposal_id = proposal_id; _current_qc.quorum_met = false; _current_qc.active_finalizers = {}; @@ -236,9 +238,10 @@ namespace eosio { namespace hotstuff { } - void qc_chain::init(name id, base_pacemaker& pacemaker, std::set my_producers){ + void qc_chain::init(name id, base_pacemaker& pacemaker, std::set my_producers, bool logging_enabled){ _id = id; + _log = logging_enabled; _pacemaker = &pacemaker; @@ -246,7 +249,7 @@ namespace eosio { namespace hotstuff { _pacemaker->register_listener(id, *this); - ilog(" === qc chain initialized ${my_producers}", ("my_producers", my_producers)); + if (_log) ilog(" === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); //auto itr = _my_producers.begin(); @@ -314,18 +317,77 @@ namespace eosio { namespace hotstuff { } + hs_vote_message qc_chain::sign_proposal(hs_proposal_message proposal, name finalizer){ + + _v_height = proposal.get_height(); + + //fc::crypto::blslib::bls_signature agg_sig; + + //if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; + + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + + fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer + + hs_vote_message v_msg = {proposal.proposal_id, finalizer, sig}; + + return v_msg; + + //ilog("signed proposal. Broadcasting for each of my producers"); + +/* auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find(finalizers.begin(), finalizers.end(), *mf_itr); + + if (prod_itr!=finalizers.end()) { + + fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer + + name n = *prod_itr; + + hs_vote_message v_msg = {proposal.proposal_id, n, sig}; + + send_hs_vote_msg(v_msg); + + }; + + mf_itr++; + + }*/ + + } + void qc_chain::process_proposal(hs_proposal_message proposal){ + auto start = fc::time_point::now(); - auto itr = _proposal_store.get().find( proposal.proposal_id ); + auto pid_itr = _proposal_store.get().find( proposal.proposal_id ); - if (itr != _proposal_store.get().end()) { - ilog("*** proposal received twice : ${proposal_id}",("proposal_id", proposal.proposal_id)); + if (pid_itr != _proposal_store.get().end()) { + ilog("*** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); return ; //already aware of proposal, nothing to do } - ilog("=== received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", + auto hgt_itr = _proposal_store.get().find( proposal.get_height() ); + + if (hgt_itr != _proposal_store.get().end()) { + ilog("*** ${id} received two different proposals at the same height (${block_num}, ${phase_counter}) : Proposal #1 : ${proposal_id_1} Proposal #2 : ${proposal_id_2}", + ("id",_id) + ("block_num", hgt_itr->block_num()) + ("phase_counter", hgt_itr->phase_counter) + ("proposal_id_1", hgt_itr->proposal_id) + ("proposal_id_2", proposal.proposal_id)); + + } + + if (_log) ilog("=== ${id} received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", + ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) ("proposal_id", proposal.proposal_id) @@ -334,15 +396,36 @@ namespace eosio { namespace hotstuff { _proposal_store.insert(proposal); //new proposal + //if I am a finalizer for this proposal and the safenode predicate for a possible vote is true, sign bool am_finalizer = am_i_finalizer(); bool node_safe = is_node_safe(proposal); bool signature_required = am_finalizer && node_safe; - //if I am a finalizer for this proposal, test safenode predicate for possible vote if (signature_required){ - - //ilog("signature required"); + + //iterate over all my finalizers and sign / broadcast for each that is in the schedule + std::vector finalizers = _pacemaker->get_finalizers(); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find(finalizers.begin(), finalizers.end(), *mf_itr); + + if (prod_itr!=finalizers.end()) { + + hs_vote_message v_msg = sign_proposal(proposal, *prod_itr); + + send_hs_vote_msg(v_msg); + + }; + + mf_itr++; + + } + + /* //ilog("signature required"); _v_height = proposal.get_height(); @@ -380,23 +463,33 @@ namespace eosio { namespace hotstuff { mf_itr++; } +*/ } + + + + //update internal state update(proposal); //check for leader change - on_leader_rotate(); + leader_rotation_check(); //ilog("process_proposal end"); + auto total_time = fc::time_point::now() - start; + + //if (_log) ilog(" ... process_proposal() total time : ${total_time}", ("total_time", total_time)); + } void qc_chain::process_vote(hs_vote_message vote){ - //check for duplicate or invalid vote, return in either case - //abstracted [...] + auto start = fc::time_point::now(); + + //todo : check for duplicate or invalid vote. We will return in either case, but keep proposals for evidence of double signing bool am_leader = am_i_leader(); //am I leader? @@ -411,9 +504,9 @@ namespace eosio { namespace hotstuff { proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); if (p_itr==_proposal_store.get().end()){ - ilog("*** couldn't find proposal"); + ilog("*** ${id} couldn't find proposal", ("id",_id)); - ilog("*** vote : ${vote}", ("vote", vote)); + ilog("*** ${id} vote : ${vote}", ("vote", vote)("id",_id)); return; } @@ -439,26 +532,28 @@ namespace eosio { namespace hotstuff { update_high_qc(_current_qc); //check for leader change - on_leader_rotate(); - + leader_rotation_check(); //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet if (_chained_mode==false && p_itr->phase_counter<3){ + if (_log) ilog(" === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); + hs_proposal_message proposal_candidate; if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); reset_qc(proposal_candidate.proposal_id); - + + if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); _pending_proposal_block = NULL_BLOCK_ID; send_hs_proposal_msg(proposal_candidate); _b_leaf = proposal_candidate.proposal_id; - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + if (_log) ilog(" === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); } @@ -466,11 +561,15 @@ namespace eosio { namespace hotstuff { } + auto total_time = fc::time_point::now() - start; + + //if (_log) ilog(" ... process_vote() total time : ${total_time}", ("total_time", total_time)); + } void qc_chain::process_new_view(hs_new_view_message new_view){ - ilog("=== process_new_view === ${qc}", ("qc", new_view.high_qc)); + if (_log) ilog("=== ${id} process_new_view === ${qc}", ("qc", new_view.high_qc)("id", _id)); update_high_qc(new_view.high_qc); } @@ -487,7 +586,7 @@ namespace eosio { namespace hotstuff { //hs_proposal_message_ptr ptr = std::make_shared(msg); - _pacemaker->send_hs_proposal_msg(msg); + _pacemaker->send_hs_proposal_msg(_id, msg); process_proposal(msg); @@ -500,7 +599,7 @@ namespace eosio { namespace hotstuff { //hs_vote_message_ptr ptr = std::make_shared(msg); - _pacemaker->send_hs_vote_msg(msg); + _pacemaker->send_hs_vote_msg(_id, msg); process_vote(msg); @@ -512,7 +611,7 @@ namespace eosio { namespace hotstuff { //hs_new_view_message_ptr ptr = std::make_shared(msg); - _pacemaker->send_hs_new_view_msg(msg); + _pacemaker->send_hs_new_view_msg(_id, msg); } @@ -522,7 +621,7 @@ namespace eosio { namespace hotstuff { //hs_new_block_message_ptr ptr = std::make_shared(msg); - _pacemaker->send_hs_new_block_msg(msg); + _pacemaker->send_hs_new_block_msg(_id, msg); } @@ -541,9 +640,7 @@ namespace eosio { namespace hotstuff { if (itr->proposal_id == ancestor){ if (counter>25) { - ilog("***"); - ilog("*** took ${counter} iterations to find ancestor ", ("counter", counter)); - ilog("***"); + ilog("*** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); } return true; @@ -553,7 +650,8 @@ namespace eosio { namespace hotstuff { } - ilog(" ***** extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", + ilog(" *** ${id} extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", + ("id",_id) ("d_proposal_id", descendant) ("a_proposal_id", ancestor)); @@ -564,8 +662,10 @@ namespace eosio { namespace hotstuff { void qc_chain::on_beat(){ std::exception_ptr eptr; try{ + + auto start = fc::time_point::now(); - ilog("=== on beat ==="); + if (_log) ilog(" === ${id} on beat === ", ("id", _id)); //std::lock_guard g( this-> _hotstuff_state_mutex ); @@ -589,8 +689,8 @@ try{ bool am_leader = am_i_leader(); - //ilog("=== am_proposer = ${am_proposer}", ("am_proposer", am_proposer)); - //ilog("=== am_leader = ${am_leader}", ("am_leader", am_leader)); + if (_log) ilog(" === ${id} am_proposer = ${am_proposer}", ("am_proposer", am_proposer)("id", _id)); + if (_log) ilog(" === ${id} am_leader = ${am_leader}", ("am_leader", am_leader)("id", _id)); if (!am_proposer && !am_leader){ @@ -611,22 +711,34 @@ try{ if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ + if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", + ("id", _id) + ("proposal_id", _current_qc.proposal_id) + ("quorum_met", _current_qc.quorum_met)); + + if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", current_block_id)); _pending_proposal_block = current_block_id; } else { + if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", + ("id", _id) + ("proposal_id", _current_qc.proposal_id) + ("quorum_met", _current_qc.quorum_met)); + hs_proposal_message proposal_candidate = new_proposal_candidate(current_block_id, 0 ); reset_qc(proposal_candidate.proposal_id); + if (_log) ilog(" === ${id} setting _pending_proposal_block to null (on_beat)", ("id", _id)); _pending_proposal_block = NULL_BLOCK_ID; send_hs_proposal_msg(proposal_candidate); _b_leaf = proposal_candidate.proposal_id; - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); + if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); } @@ -642,6 +754,10 @@ try{ send_hs_new_block_msg(block_candidate); } + + auto total_time = fc::time_point::now() - start; + + //if (_log) ilog(" ... on_beat() total time : ${total_time}", ("total_time", total_time)); //ilog(" === end of on_beat"); } @@ -664,7 +780,7 @@ handle_eptr(eptr); _high_qc = high_qc; _b_leaf = _high_qc.proposal_id; - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } else { @@ -692,7 +808,7 @@ handle_eptr(eptr); _high_qc = high_qc; _b_leaf = _high_qc.proposal_id; - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); + if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } @@ -702,9 +818,9 @@ handle_eptr(eptr); } - void qc_chain::on_leader_rotate(){ + void qc_chain::leader_rotation_check(){ - //ilog("on_leader_rotate"); + //ilog("leader_rotation_check"); //verify if leader changed @@ -713,13 +829,16 @@ handle_eptr(eptr); if (current_leader != next_leader){ - ilog("/// rotating leader : ${old_leader} -> ${new_leader} ", - ("old_leader", current_leader)("new_leader", next_leader)); + if (_log) ilog(" /// ${id} rotating leader : ${old_leader} -> ${new_leader} ", + ("id", _id) + ("old_leader", current_leader) + ("new_leader", next_leader)); //leader changed, we send our new_view message reset_qc(NULL_PROPOSAL_ID); + if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); _pending_proposal_block = NULL_BLOCK_ID; hs_new_view_message new_view; @@ -805,7 +924,7 @@ handle_eptr(eptr); } else { - ilog("not locked on anything, liveness and safety are true"); + if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); //if we're not locked on anything, means the protocol just activated or chain just launched liveness_check = true; @@ -836,7 +955,7 @@ try{ //ilog(" === end of on_hs_proposal_msg"); } catch (...){ - ilog("error during on_hs_proposal_msg"); + ilog(" *** ${id} error during on_hs_proposal_msg", ("id",_id)); eptr = std::current_exception(); // capture } handle_eptr(eptr); @@ -856,7 +975,7 @@ try{ //ilog(" === end of on_hs_vote_msg"); } catch (...){ - ilog("error during on_hs_vote_msg"); + ilog(" *** ${id} error during on_hs_vote_msg", ("id",_id)); eptr = std::current_exception(); // capture } handle_eptr(eptr); @@ -876,7 +995,7 @@ try{ //ilog(" === end of on_hs_new_view_msg"); } catch (...){ - ilog("error during on_hs_new_view_msg"); + ilog(" *** ${id} error during on_hs_new_view_msg", ("id",_id)); eptr = std::current_exception(); // capture } handle_eptr(eptr); @@ -896,7 +1015,7 @@ try{ //ilog(" === end of on_hs_new_block_msg"); } catch (...){ - ilog("error during on_hs_new_block_msg"); + ilog(" *** ${id} error during on_hs_new_block_msg", ("id",_id)); eptr = std::current_exception(); // capture } handle_eptr(eptr); @@ -910,7 +1029,7 @@ handle_eptr(eptr); //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ - ilog("*** proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)); + if (_log) ilog(" === ${id} proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)("id", _id)); return; } @@ -924,7 +1043,7 @@ handle_eptr(eptr); update_high_qc(proposal.justify); if (chain_length<1){ - ilog("*** qc chain length is 0"); + if (_log) ilog(" === ${id} qc chain length is 0", ("id", _id)); return; } @@ -932,7 +1051,7 @@ handle_eptr(eptr); hs_proposal_message b_2 = *itr; if (chain_length<2){ - ilog("*** qc chain length is 1"); + if (_log) ilog(" === ${id} qc chain length is 1", ("id", _id)); return; } @@ -946,12 +1065,12 @@ handle_eptr(eptr); //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); _b_lock = b_1.proposal_id; //commit phase on b1 - ilog("=== _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)); + if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); } if (chain_length<3){ - ilog("*** qc chain length is 2"); + if (_log) ilog(" === ${id} qc chain length is 2",("id", _id)); return; } @@ -986,11 +1105,11 @@ handle_eptr(eptr); } else { - ilog("*** could not verify direct parent relationship"); + ilog(" *** ${id} could not verify direct parent relationship", ("id",_id)); - ilog("*** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); - ilog("*** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); - ilog("*** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); + ilog(" *** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); + ilog(" *** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); + ilog(" *** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); } @@ -1007,7 +1126,8 @@ handle_eptr(eptr); auto itr = _proposal_store.get().begin(); - ilog("erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + ("id", _id) ("block_num", itr->block_num()) ("phase_counter", itr->phase_counter) ("block_id", itr->block_id) @@ -1058,7 +1178,8 @@ handle_eptr(eptr); } - ilog("=== committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", + if (_log) ilog(" === ${id} committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", + ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) ("block_id", proposal.block_id) diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index b2084487dc..200608a2b5 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -14,152 +14,425 @@ using namespace eosio::hotstuff; using std::cout; -std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, - 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, - 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; +std::vector ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c39"), + block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530684"), + block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf330"), + block_id_type("00000004235f391d91d5da938cfa8c4738d92da6c007da596f1db05c37d38866"), + block_id_type("00000005485fa018c16b6150aed839bdd4cbc2149f70191e89f2b19fe711b1c0"), + block_id_type("00000006161b9c79797059bbdcbf49614bbdca33d35b8099ffa250583dc41d9d"), + block_id_type("00000007ffd04a602236843f842827c2ac2aa61d586b7ebc8cc3c276921b55d9"), + block_id_type("000000085e8b9b158801fea3f7b2b627734805b9192568b67d7d00d676e427e3"), + block_id_type("0000000979b05f273f2885304f952aaa6f47d56985e003ec35c22472682ad3a2"), + block_id_type("0000000a703d6a104c722b8bc2d7227b90a35d08835343564c2fd66eb9dcf999"), + block_id_type("0000000ba7ef2e432d465800e53d1da982f2816c051153f9054960089d2f37d8") }; + +//list of unique replicas for our test +std::vector unique_replicas{ "bpa"_n, "bpb"_n, "bpc"_n, + "bpd"_n, "bpe"_n, "bpf"_n, + "bpg"_n, "bph"_n, "bpi"_n, + "bpj"_n, "bpk"_n ,"bpl"_n, + "bpm"_n, "bpn"_n, "bpo"_n, + "bpp"_n, "bpq"_n, "bpr"_n, + "bps"_n, "bpt"_n, "bpu"_n }; + +std::vector> _qc_chains; + +void initialize_qc_chains(test_pacemaker& tpm, std::vector loggers, std::vector replicas){ -fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); + + _qc_chains.clear(); + + for (name r : replicas){ + + _qc_chains.push_back(std::make_pair(r, qc_chain())); + + } + + int counter = 0; + + auto itr = _qc_chains.begin(); + + while (itr!=_qc_chains.end()){ + + bool log = false; + + auto found = std::find(loggers.begin(), loggers.end(), replicas[counter]); + + if (found!=loggers.end()) log = true; + + itr->second.init(replicas[counter], tpm, {replicas[counter]}, log); + + itr++; + counter++; + + } + +} +void print_msg_queue_size(test_pacemaker &tpm){ -fc::sha256 message_1 = fc::sha256("000000000000000118237d3d79f3c684c031a9844c27e6b95c6d27d8a5f401a1"); -fc::sha256 message_2 = fc::sha256("0000000000000002fb2129a8f7c9091ae983bc817002ffab21cd98eab2147029"); + std::cout << "\n"; + std::cout << " message queue size : " << tpm._pending_message_queue.size() << "\n"; + std::cout << "\n"; + +} + +void print_pm_state(test_pacemaker &tpm){ + + std::cout << "\n"; + + std::cout << " leader : " << tpm.get_leader() << "\n"; + + std::cout << " next leader : " << tpm.get_next_leader() << "\n"; + + std::cout << " proposer : " << tpm.get_proposer() << "\n"; + + std::cout << " current block id : " << tpm.get_current_block_id().str() << "\n"; + + std::cout << "\n"; + +} + +void print_bp_state(name bp, std::string message){ + + std::cout << "\n"; + std::cout << message; + std::cout << "\n"; + + auto qcc = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == bp; }); + + auto leaf_itr = qcc->second._proposal_store.get().find( qcc->second._b_leaf ); + auto qc_itr = qcc->second._proposal_store.get().find( qcc->second._high_qc.proposal_id ); + auto lock_itr = qcc->second._proposal_store.get().find( qcc->second._b_lock ); + auto exec_itr = qcc->second._proposal_store.get().find( qcc->second._b_exec ); + + if (leaf_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << qcc->second._b_leaf.str() << " block_num : " << leaf_itr->block_num() << ", phase : " << unsigned(leaf_itr->phase_counter) << "\n"; + else std::cout << " - No b_leaf value " << "\n"; + + if (qc_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current high_qc is : " << qcc->second._high_qc.proposal_id.str() << " block_num : " << qc_itr->block_num() << ", phase : " << unsigned(qc_itr->phase_counter) << "\n"; + else std::cout << " - No high_qc value " << "\n"; + + if (lock_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_lock is : " << qcc->second._b_lock.str() << " block_num : " << lock_itr->block_num() << ", phase : " << unsigned(lock_itr->phase_counter) << "\n"; + else std::cout << " - No b_lock value " << "\n"; + + if (exec_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_exec is : " << qcc->second._b_exec.str() << " block_num : " << exec_itr->block_num() << ", phase : " << unsigned(exec_itr->phase_counter) << "\n"; + else std::cout << " - No b_exec value " << "\n"; + + std::cout << "\n"; + +} BOOST_AUTO_TEST_SUITE(hotstuff) -BOOST_AUTO_TEST_CASE(hotstuff_tests) try { - - std::vector ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c39"), - block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530684"), - block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf330"), - block_id_type("00000004235f391d91d5da938cfa8c4738d92da6c007da596f1db05c37d38866"), - block_id_type("00000005485fa018c16b6150aed839bdd4cbc2149f70191e89f2b19fe711b1c0"), - block_id_type("00000006161b9c79797059bbdcbf49614bbdca33d35b8099ffa250583dc41d9d"), - block_id_type("00000007ffd04a602236843f842827c2ac2aa61d586b7ebc8cc3c276921b55d9"), - block_id_type("000000085e8b9b158801fea3f7b2b627734805b9192568b67d7d00d676e427e3"), - block_id_type("0000000979b05f273f2885304f952aaa6f47d56985e003ec35c22472682ad3a2"), - block_id_type("0000000a703d6a104c722b8bc2d7227b90a35d08835343564c2fd66eb9dcf999"), - block_id_type("0000000ba7ef2e432d465800e53d1da982f2816c051153f9054960089d2f37d8") }; - - //list of unique replicas for our test - std::vector unique_replicas{ "bpa"_n, "bpb"_n, "bpc"_n, - "bpd"_n, "bpe"_n, "bpf"_n, - "bpg"_n, "bph"_n, "bpi"_n, - "bpj"_n, "bpk"_n ,"bpl"_n, - "bpm"_n, "bpn"_n, "bpo"_n, - "bpp"_n, "bpq"_n, "bpr"_n, - "bps"_n, "bpt"_n, "bpu"_n }; - - std::vector> qc_chains; +BOOST_AUTO_TEST_CASE(hotstuff_1) try { test_pacemaker tpm; - std::cout << "Running Hotstuff Tests..." << "\n"; + initialize_qc_chains(tpm, {"bpa"_n}, unique_replicas); - for (name r : unique_replicas){ - - qc_chains.push_back(std::make_pair(r, qc_chain())); - - } + tpm.set_proposer("bpa"_n); + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); - int counter = 0; + auto qcc_bpa = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); - auto itr = qc_chains.begin(); + tpm.set_current_block_id(ids[0]); //first block - while (itr!=qc_chains.end()){ + tpm.beat(); //produce first block and associated proposal - itr->second.init(unique_replicas[counter], tpm, {unique_replicas[counter]}); + tpm.propagate(); //propagate proposal to replicas (prepare on first block) - itr++; - counter++; + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - } + tpm.propagate(); //propagate votes on proposal (prepareQC on first block) - tpm.set_proposer("bpa"_n); - tpm.set_leader("bpa"_n); - tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); + tpm.propagate(); //propagate proposal to replicas (precommit on first block) - std::cout << "test_pacemaker configured." << "\n"; + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.set_current_block_id(ids[0]); - - std::cout << "test_pacemaker got qcc" << "\n"; - - auto qc = std::find_if(qc_chains.begin(), qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + tpm.propagate(); //propagating votes on new proposal (precommitQC on first block) - tpm.beat(); + tpm.propagate(); //propagate proposal to replicas (commit on first block) - std::cout << "test_pacemaker on_beat event chain executed." << "\n"; + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.propagate(); //propagating new proposal message + tpm.propagate(); //propagating votes on new proposal (commitQC on first block) - std::cout << " --- propagated new proposal message (phase 0)." << "\n"; + tpm.propagate(); //propagate proposal to replicas (decide on first block) - tpm.propagate(); //propagating votes on new proposal + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - std::cout << " --- propagated votes on new proposal." << "\n"; + tpm.propagate(); //propagating votes on new proposal (decide on first block) - qc_chain::proposal_store_type::nth_index<0>::type::iterator prop_itr = qc->second._proposal_store.get().find( qc->second._high_qc.proposal_id ); + tpm.set_current_block_id(ids[1]); //second block - std::cout << "bpa current high_qc is : " << qc->second._high_qc.proposal_id.str() << ",id : " << prop_itr->block_id.str() << ", phase : " << unsigned(prop_itr->phase_counter) << "\n"; + tpm.beat(); //produce second block and associated proposal - std::cout << "bpa current _b_leaf is : " << qc->second._b_leaf.str() << "\n"; - std::cout << "bpa current _b_lock is : " << qc->second._b_lock.str() << "\n"; - std::cout << "bpa current _b_exec is : " << qc->second._b_exec.str() << "\n"; - - tpm.propagate(); //propagating updated proposal with qc + tpm.propagate(); //propagate proposal to replicas (prepare on second block) - std::cout << " --- propagated propagating updated proposal with qc (phase 1)." << "\n"; + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - tpm.propagate(); //propagating votes on new proposal + tpm.propagate(); //propagate votes on proposal (prepareQC on second block) - std::cout << " --- propagated votes on new proposal." << "\n"; + tpm.propagate(); //propagate proposal to replicas (precommit on second block) - prop_itr = qc->second._proposal_store.get().find( qc->second._high_qc.proposal_id ); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - std::cout << "bpa current high_qc is : " << qc->second._high_qc.proposal_id.str() << ",id : " << prop_itr->block_id.str() << ", phase : " << unsigned(prop_itr->phase_counter) << "\n"; + tpm.propagate(); //propagating votes on new proposal (precommitQC on second block) - std::cout << "bpa current _b_leaf is : " << qc->second._b_leaf.str() << "\n"; - std::cout << "bpa current _b_lock is : " << qc->second._b_lock.str() << "\n"; - std::cout << "bpa current _b_exec is : " << qc->second._b_exec.str() << "\n"; - - tpm.propagate(); //propagating updated proposal with qc + tpm.propagate(); //propagate proposal to replicas (commit on second block) - std::cout << " --- propagated propagating updated proposal with qc (phase 2)." << "\n"; + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - tpm.propagate(); //propagating votes on new proposal + tpm.propagate(); //propagating votes on new proposal (commitQC on second block) - std::cout << " --- propagated votes on new proposal." << "\n"; + tpm.propagate(); //propagate proposal to replicas (decide on second block) - prop_itr = qc->second._proposal_store.get().find( qc->second._high_qc.proposal_id ); +//print_bp_state("bpa"_n, ""); +//print_bp_state("bpb"_n, ""); - std::cout << "bpa current high_qc is : " << qc->second._high_qc.proposal_id.str() << ",id : " << prop_itr->block_id.str() << ", phase : " << unsigned(prop_itr->phase_counter) << "\n"; + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - std::cout << "bpa current _b_leaf is : " << qc->second._b_leaf.str() << "\n"; - std::cout << "bpa current _b_lock is : " << qc->second._b_lock.str() << "\n"; - std::cout << "bpa current _b_exec is : " << qc->second._b_exec.str() << "\n"; - - tpm.propagate(); //propagating updated proposal with qc +//print_msg_queue_size(tpm); - std::cout << " --- propagated propagating updated proposal with qc (phase 3)." << "\n"; + tpm.propagate(); //propagate proposal to replicas (decide on second block) - tpm.propagate(); //propagating votes on new proposal +//print_bp_state("bpa"_n, ""); +//print_bp_state("bpb"_n, ""); - std::cout << " --- propagated votes on new proposal." << "\n"; - prop_itr = qc->second._proposal_store.get().find( qc->second._high_qc.proposal_id ); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - std::cout << "bpa current high_qc is : " << qc->second._high_qc.proposal_id.str() << ",id : " << prop_itr->block_id.str() << ", phase : " << unsigned(prop_itr->phase_counter) << "\n"; + //check bpb as well + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - std::cout << "bpa current _b_leaf is : " << qc->second._b_leaf.str() << "\n"; - std::cout << "bpa current _b_lock is : " << qc->second._b_lock.str() << "\n"; - std::cout << "bpa current _b_exec is : " << qc->second._b_exec.str() << "\n"; - - //std::cout << "test_pacemaker messages propagated." << "\n"; - BOOST_CHECK_EQUAL(false, false); +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_2) try { + + test_pacemaker tpm; + + initialize_qc_chains(tpm, {"bpa"_n}, unique_replicas); + + tpm.set_proposer("bpa"_n); + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); + + auto qcc_bpa = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + + tpm.set_current_block_id(ids[0]); //first block + + tpm.beat(); //produce first block and associated proposal + + tpm.propagate(); //propagate proposal to replicas (prepare on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.propagate(); //propagate votes on proposal (prepareQC on first block) + + tpm.propagate(); //propagate proposal to replicas (precommit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.set_current_block_id(ids[1]); //second block + + tpm.beat(); //produce second block and associated proposal + + tpm.propagate(); //propagate proposal to replicas (prepare on second block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.propagate(); //propagate votes on proposal (prepareQC on second block) + + tpm.propagate(); //propagate proposal to replicas (precommit on second block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.set_current_block_id(ids[2]); //second block + + tpm.beat(); //produce third block and associated proposal + + tpm.propagate(); //propagating votes on new proposal (precommitQC on third block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.propagate(); //propagating votes on new proposal (precommitQC on third block) + + tpm.propagate(); //propagating votes on new proposal (precommitQC on third block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + + //check bpb as well + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_3) try { + + test_pacemaker tpm; + + initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, unique_replicas); + + tpm.set_proposer("bpa"_n); + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); + + auto qcc_bpa = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + + tpm.set_current_block_id(ids[0]); //first block + + tpm.beat(); //produce first block and associated proposal + + tpm.propagate(); //propagate proposal to replicas (prepare on first block) +print_bp_state("bpa"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.propagate(); //propagate votes on proposal (prepareQC on first block) + + tpm.propagate(); //propagate proposal to replicas (precommit on first block) +print_bp_state("bpa"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.propagate(); //propagating votes on new proposal (precommitQC on first block) + + tpm.propagate(); //propagate proposal to replicas (commit on first block) +print_bp_state("bpa"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.set_next_leader("bpb"_n); + + tpm.propagate(); //propagating votes on new proposal (commitQC on first block) + + tpm.propagate(); //propagate proposal to replicas (decide on first block) +print_bp_state("bpa"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.propagate(); //propagating votes on new proposal (decide on first block) + + tpm.set_proposer("bpb"_n); + tpm.set_leader("bpb"_n); + + tpm.set_current_block_id(ids[1]); //second block + + tpm.beat(); //produce second block and associated proposal + + tpm.propagate(); //propagate proposal to replicas (prepare on second block) +print_bp_state("bpb"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.propagate(); //propagate votes on proposal (prepareQC on second block) + + tpm.propagate(); //propagate proposal to replicas (precommit on second block) +print_bp_state("bpb"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + + tpm.propagate(); //propagating votes on new proposal (precommitQC on second block) + + tpm.propagate(); //propagate proposal to replicas (commit on second block) +print_bp_state("bpb"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + + tpm.propagate(); //propagating votes on new proposal (commitQC on second block) + + tpm.propagate(); //propagate proposal to replicas (decide on second block) +print_bp_state("bpb"_n, ""); +print_bp_state("bpa"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + + //check bpa as well + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); } FC_LOG_AND_RETHROW(); diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test_pacemaker.cpp index 01ff62862f..24824bf3fd 100644 --- a/libraries/hotstuff/test_pacemaker.cpp +++ b/libraries/hotstuff/test_pacemaker.cpp @@ -41,11 +41,15 @@ namespace eosio { namespace hotstuff { _quorum_threshold = threshold; } + void test_pacemaker::add_message_to_queue(hotstuff_message msg){ + _pending_message_queue.push_back(msg); + } + void test_pacemaker::propagate(){ int count = 1; - ilog(" === propagate ${count} messages", ("count", _pending_message_queue.size())); + //ilog(" === propagate ${count} messages", ("count", _pending_message_queue.size())); _message_queue = _pending_message_queue; @@ -64,12 +68,12 @@ namespace eosio { namespace hotstuff { while (msg_itr!=_message_queue.end()){ - ilog(" === propagating message ${count} : type : ${index}", ("count", count) ("index", msg_itr->index())); + //ilog(" === propagating message ${count} : type : ${index}", ("count", count) ("index", msg_itr->index())); - if (msg_itr->index() == 0) on_hs_proposal_msg(std::get(*msg_itr)); - else if (msg_itr->index() == 1) on_hs_vote_msg(std::get(*msg_itr)); - else if (msg_itr->index() == 2) on_hs_new_block_msg(std::get(*msg_itr)); - else if (msg_itr->index() == 3) on_hs_new_view_msg(std::get(*msg_itr)); + if (msg_itr->second.index() == 0) on_hs_proposal_msg(msg_itr->first, std::get(msg_itr->second)); + else if (msg_itr->second.index() == 1) on_hs_vote_msg(msg_itr->first, std::get(msg_itr->second)); + else if (msg_itr->second.index() == 2) on_hs_new_block_msg(msg_itr->first, std::get(msg_itr->second)); + else if (msg_itr->second.index() == 3) on_hs_new_view_msg(msg_itr->first, std::get(msg_itr->second)); msg_itr++; @@ -93,7 +97,7 @@ namespace eosio { namespace hotstuff { //ilog(" === after erase"); - ilog(" === end propagate"); + //ilog(" === end propagate"); } @@ -150,7 +154,7 @@ namespace eosio { namespace hotstuff { } else { - ilog("new listener ${name}", ("name", name)); + //ilog("new listener ${name}", ("name", name)); //_unique_replicas.push_back(name); @@ -191,35 +195,35 @@ namespace eosio { namespace hotstuff { }; - void test_pacemaker::send_hs_proposal_msg(hs_proposal_message msg){ + void test_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ //ilog("queuing hs_proposal_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); - _pending_message_queue.push_back(msg); + _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_vote_msg(hs_vote_message msg){ + void test_pacemaker::send_hs_vote_msg(name id, hs_vote_message msg){ //ilog("queuing hs_vote_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); - _pending_message_queue.push_back(msg); + _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_block_msg(hs_new_block_message msg){ + void test_pacemaker::send_hs_new_block_msg(name id, hs_new_block_message msg){ - _pending_message_queue.push_back(msg); + _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_view_msg(hs_new_view_message msg){ + void test_pacemaker::send_hs_new_view_msg(name id, hs_new_view_message msg){ - _pending_message_queue.push_back(msg); + _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::on_hs_proposal_msg(hs_proposal_message msg){ + void test_pacemaker::on_hs_proposal_msg(name id, hs_proposal_message msg){ //ilog(" === on_hs_proposal_msg"); auto qc_itr = _qcc_store.begin(); @@ -230,7 +234,7 @@ namespace eosio { namespace hotstuff { if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); - if (qc_itr->_active) qc_itr->_qc_chain->on_hs_proposal_msg(msg); + if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_proposal_msg(msg); qc_itr++; @@ -240,7 +244,7 @@ namespace eosio { namespace hotstuff { } - void test_pacemaker::on_hs_vote_msg(hs_vote_message msg){ + void test_pacemaker::on_hs_vote_msg(name id, hs_vote_message msg){ //ilog(" === on_hs_vote_msg"); auto qc_itr = _qcc_store.begin(); @@ -251,7 +255,7 @@ namespace eosio { namespace hotstuff { if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); - if (qc_itr->_active) qc_itr->_qc_chain->on_hs_vote_msg(msg); + if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_vote_msg(msg); qc_itr++; } @@ -260,7 +264,7 @@ namespace eosio { namespace hotstuff { } - void test_pacemaker::on_hs_new_block_msg(hs_new_block_message msg){ + void test_pacemaker::on_hs_new_block_msg(name id, hs_new_block_message msg){ //ilog(" === on_hs_new_block_msg"); auto qc_itr = _qcc_store.begin(); @@ -271,7 +275,7 @@ namespace eosio { namespace hotstuff { if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); - if (qc_itr->_active) qc_itr->_qc_chain->on_hs_new_block_msg(msg); + if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_block_msg(msg); qc_itr++; } @@ -280,7 +284,7 @@ namespace eosio { namespace hotstuff { } - void test_pacemaker::on_hs_new_view_msg(hs_new_view_message msg){ + void test_pacemaker::on_hs_new_view_msg(name id, hs_new_view_message msg){ //ilog(" === on_hs_new_view_msg"); auto qc_itr = _qcc_store.begin(); @@ -291,7 +295,7 @@ namespace eosio { namespace hotstuff { if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); - if (qc_itr->_active) qc_itr->_qc_chain->on_hs_new_view_msg(msg); + if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_view_msg(msg); qc_itr++; } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index af45b6f2b0..27659d4b3e 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1019,7 +1019,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->_chain_pacemaker.init(&chain); - my->_qc_chain.init("main"_n, my->_chain_pacemaker, my->_producers); + my->_qc_chain.init("main"_n, my->_chain_pacemaker, my->_producers, true); } FC_LOG_AND_RETHROW() } @@ -2523,19 +2523,19 @@ static auto maybe_make_debug_time_logger() -> std::optional Date: Fri, 24 Mar 2023 12:48:05 +0000 Subject: [PATCH 014/151] Fixed scope issue in unit tests --- .../include/eosio/hotstuff/qc_chain.hpp | 27 +-- libraries/hotstuff/qc_chain.cpp | 11 +- libraries/hotstuff/test/CMakeLists.txt | 2 + libraries/hotstuff/test/test_hotstuff.cpp | 157 ++++++++++-------- 4 files changed, 112 insertions(+), 85 deletions(-) diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index b43034936c..8eece66ec7 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -44,18 +44,6 @@ namespace eosio { namespace hotstuff { } }; - qc_chain(){ - //ilog("_high_qc : ${qc_id}", ("qc_id", _high_qc.proposal_id)); - - }; - - ~qc_chain(){ - -/* if (_pacemaker == NULL) delete _pacemaker; - - _pacemaker = 0;*/ - - }; //todo : remove. bls12-381 key used for testing purposes std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, @@ -171,6 +159,21 @@ namespace eosio { namespace hotstuff { void gc_proposals(uint64_t cutoff); //garbage collection of old proposals + qc_chain(){ + //ilog("_high_qc : ${qc_id}", ("qc_id", _high_qc.proposal_id)); + + }; + + ~qc_chain(){ + + _proposal_store.get().clear(); + _proposal_store.get().clear(); + +/* if (_pacemaker == NULL) delete _pacemaker; + + _pacemaker = 0;*/ + + }; private : diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index ead986948c..cfe18e0c3c 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -1060,7 +1060,16 @@ handle_eptr(eptr); hs_proposal_message b_1 = *itr; //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock - if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ + + if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height} b_lock height ${b_lock_height}", + ("id", _id) + ("_b_lock", _b_lock) + ("b_1_height", b_1.block_num()) + ("b_1_phase", b_1.phase_counter) + ("b_lock_height", b_lock->block_num()) + ("b_lock_phase", b_lock->phase_counter)); + + if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); _b_lock = b_1.proposal_id; //commit phase on b1 diff --git a/libraries/hotstuff/test/CMakeLists.txt b/libraries/hotstuff/test/CMakeLists.txt index 20a940b112..8ef773c64a 100644 --- a/libraries/hotstuff/test/CMakeLists.txt +++ b/libraries/hotstuff/test/CMakeLists.txt @@ -2,3 +2,5 @@ add_executable( test_hotstuff test_hotstuff.cpp) target_link_libraries( test_hotstuff hotstuff fc Boost::unit_test_framework) add_test(NAME test_hotstuff COMMAND test_hotstuff WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) +set_property(TEST test_hotstuff PROPERTY LABELS nonparallelizable_tests) + diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 200608a2b5..0849015815 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -35,94 +35,99 @@ std::vector unique_replicas{ "bpa"_n, "bpb"_n, "bpc"_n, "bpp"_n, "bpq"_n, "bpr"_n, "bps"_n, "bpt"_n, "bpu"_n }; -std::vector> _qc_chains; -void initialize_qc_chains(test_pacemaker& tpm, std::vector loggers, std::vector replicas){ +class hotstuff_test_state { +public: - - _qc_chains.clear(); + std::vector> _qc_chains; - for (name r : replicas){ - - _qc_chains.push_back(std::make_pair(r, qc_chain())); - - } + void initialize_qc_chains(test_pacemaker& tpm, std::vector loggers, std::vector replicas){ - int counter = 0; + _qc_chains.clear(); - auto itr = _qc_chains.begin(); + for (name r : replicas){ + + _qc_chains.push_back(std::make_pair(r, qc_chain())); + + } - while (itr!=_qc_chains.end()){ + int counter = 0; - bool log = false; + auto itr = _qc_chains.begin(); - auto found = std::find(loggers.begin(), loggers.end(), replicas[counter]); + while (itr!=_qc_chains.end()){ - if (found!=loggers.end()) log = true; + bool log = false; - itr->second.init(replicas[counter], tpm, {replicas[counter]}, log); + auto found = std::find(loggers.begin(), loggers.end(), replicas[counter]); - itr++; - counter++; + if (found!=loggers.end()) log = true; - } + itr->second.init(replicas[counter], tpm, {replicas[counter]}, log); -} + itr++; + counter++; -void print_msg_queue_size(test_pacemaker &tpm){ + } - std::cout << "\n"; + } - std::cout << " message queue size : " << tpm._pending_message_queue.size() << "\n"; + void print_msg_queue_size(test_pacemaker &tpm){ - std::cout << "\n"; + std::cout << "\n"; -} + std::cout << " message queue size : " << tpm._pending_message_queue.size() << "\n"; + + std::cout << "\n"; + + } -void print_pm_state(test_pacemaker &tpm){ + void print_pm_state(test_pacemaker &tpm){ - std::cout << "\n"; + std::cout << "\n"; - std::cout << " leader : " << tpm.get_leader() << "\n"; + std::cout << " leader : " << tpm.get_leader() << "\n"; - std::cout << " next leader : " << tpm.get_next_leader() << "\n"; + std::cout << " next leader : " << tpm.get_next_leader() << "\n"; - std::cout << " proposer : " << tpm.get_proposer() << "\n"; + std::cout << " proposer : " << tpm.get_proposer() << "\n"; - std::cout << " current block id : " << tpm.get_current_block_id().str() << "\n"; + std::cout << " current block id : " << tpm.get_current_block_id().str() << "\n"; - std::cout << "\n"; + std::cout << "\n"; -} + } -void print_bp_state(name bp, std::string message){ - - std::cout << "\n"; - std::cout << message; - std::cout << "\n"; + void print_bp_state(name bp, std::string message){ + + std::cout << "\n"; + std::cout << message; + std::cout << "\n"; - auto qcc = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == bp; }); + auto qcc = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == bp; }); - auto leaf_itr = qcc->second._proposal_store.get().find( qcc->second._b_leaf ); - auto qc_itr = qcc->second._proposal_store.get().find( qcc->second._high_qc.proposal_id ); - auto lock_itr = qcc->second._proposal_store.get().find( qcc->second._b_lock ); - auto exec_itr = qcc->second._proposal_store.get().find( qcc->second._b_exec ); - - if (leaf_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << qcc->second._b_leaf.str() << " block_num : " << leaf_itr->block_num() << ", phase : " << unsigned(leaf_itr->phase_counter) << "\n"; - else std::cout << " - No b_leaf value " << "\n"; + auto leaf_itr = qcc->second._proposal_store.get().find( qcc->second._b_leaf ); + auto qc_itr = qcc->second._proposal_store.get().find( qcc->second._high_qc.proposal_id ); + auto lock_itr = qcc->second._proposal_store.get().find( qcc->second._b_lock ); + auto exec_itr = qcc->second._proposal_store.get().find( qcc->second._b_exec ); + + if (leaf_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << qcc->second._b_leaf.str() << " block_num : " << leaf_itr->block_num() << ", phase : " << unsigned(leaf_itr->phase_counter) << "\n"; + else std::cout << " - No b_leaf value " << "\n"; - if (qc_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current high_qc is : " << qcc->second._high_qc.proposal_id.str() << " block_num : " << qc_itr->block_num() << ", phase : " << unsigned(qc_itr->phase_counter) << "\n"; - else std::cout << " - No high_qc value " << "\n"; + if (qc_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current high_qc is : " << qcc->second._high_qc.proposal_id.str() << " block_num : " << qc_itr->block_num() << ", phase : " << unsigned(qc_itr->phase_counter) << "\n"; + else std::cout << " - No high_qc value " << "\n"; - if (lock_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_lock is : " << qcc->second._b_lock.str() << " block_num : " << lock_itr->block_num() << ", phase : " << unsigned(lock_itr->phase_counter) << "\n"; - else std::cout << " - No b_lock value " << "\n"; + if (lock_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_lock is : " << qcc->second._b_lock.str() << " block_num : " << lock_itr->block_num() << ", phase : " << unsigned(lock_itr->phase_counter) << "\n"; + else std::cout << " - No b_lock value " << "\n"; - if (exec_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_exec is : " << qcc->second._b_exec.str() << " block_num : " << exec_itr->block_num() << ", phase : " << unsigned(exec_itr->phase_counter) << "\n"; - else std::cout << " - No b_exec value " << "\n"; + if (exec_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_exec is : " << qcc->second._b_exec.str() << " block_num : " << exec_itr->block_num() << ", phase : " << unsigned(exec_itr->phase_counter) << "\n"; + else std::cout << " - No b_exec value " << "\n"; - std::cout << "\n"; + std::cout << "\n"; -} + } + +}; BOOST_AUTO_TEST_SUITE(hotstuff) @@ -130,15 +135,17 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { test_pacemaker tpm; - initialize_qc_chains(tpm, {"bpa"_n}, unique_replicas); + hotstuff_test_state ht; + + ht.initialize_qc_chains(tpm, {"bpa"_n}, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); tpm.set_next_leader("bpa"_n); tpm.set_finalizers(unique_replicas); - auto qcc_bpa = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); - auto qcc_bpb = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); tpm.set_current_block_id(ids[0]); //first block @@ -246,15 +253,17 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { test_pacemaker tpm; - initialize_qc_chains(tpm, {"bpa"_n}, unique_replicas); + hotstuff_test_state ht; + + ht.initialize_qc_chains(tpm, {"bpa"_n}, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); tpm.set_next_leader("bpa"_n); tpm.set_finalizers(unique_replicas); - auto qcc_bpa = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); - auto qcc_bpb = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); tpm.set_current_block_id(ids[0]); //first block @@ -327,22 +336,26 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { test_pacemaker tpm; - initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, unique_replicas); + hotstuff_test_state ht; + + ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, unique_replicas); + +ht.print_msg_queue_size(tpm); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); tpm.set_next_leader("bpa"_n); tpm.set_finalizers(unique_replicas); - auto qcc_bpa = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); - auto qcc_bpb = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); tpm.set_current_block_id(ids[0]); //first block tpm.beat(); //produce first block and associated proposal tpm.propagate(); //propagate proposal to replicas (prepare on first block) -print_bp_state("bpa"_n, ""); +ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -352,7 +365,7 @@ print_bp_state("bpa"_n, ""); tpm.propagate(); //propagate votes on proposal (prepareQC on first block) tpm.propagate(); //propagate proposal to replicas (precommit on first block) -print_bp_state("bpa"_n, ""); +ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -362,7 +375,7 @@ print_bp_state("bpa"_n, ""); tpm.propagate(); //propagating votes on new proposal (precommitQC on first block) tpm.propagate(); //propagate proposal to replicas (commit on first block) -print_bp_state("bpa"_n, ""); +ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -374,7 +387,7 @@ print_bp_state("bpa"_n, ""); tpm.propagate(); //propagating votes on new proposal (commitQC on first block) tpm.propagate(); //propagate proposal to replicas (decide on first block) -print_bp_state("bpa"_n, ""); +ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -391,7 +404,7 @@ print_bp_state("bpa"_n, ""); tpm.beat(); //produce second block and associated proposal tpm.propagate(); //propagate proposal to replicas (prepare on second block) -print_bp_state("bpb"_n, ""); +ht.print_bp_state("bpb"_n, ""); BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -401,7 +414,7 @@ print_bp_state("bpb"_n, ""); tpm.propagate(); //propagate votes on proposal (prepareQC on second block) tpm.propagate(); //propagate proposal to replicas (precommit on second block) -print_bp_state("bpb"_n, ""); +ht.print_bp_state("bpb"_n, ""); BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); @@ -411,7 +424,7 @@ print_bp_state("bpb"_n, ""); tpm.propagate(); //propagating votes on new proposal (precommitQC on second block) tpm.propagate(); //propagate proposal to replicas (commit on second block) -print_bp_state("bpb"_n, ""); +ht.print_bp_state("bpb"_n, ""); BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); @@ -421,8 +434,8 @@ print_bp_state("bpb"_n, ""); tpm.propagate(); //propagating votes on new proposal (commitQC on second block) tpm.propagate(); //propagate proposal to replicas (decide on second block) -print_bp_state("bpb"_n, ""); -print_bp_state("bpa"_n, ""); +ht.print_bp_state("bpb"_n, ""); +ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); From ffd1d1f8caf7ee3a80878497672a4e2ff92170d5 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 24 Mar 2023 14:44:22 +0000 Subject: [PATCH 015/151] Fixed scope issue in unit tests --- libraries/hotstuff/test/test_hotstuff.cpp | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 0849015815..253ffdf5b9 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -131,7 +131,7 @@ class hotstuff_test_state { BOOST_AUTO_TEST_SUITE(hotstuff) -BOOST_AUTO_TEST_CASE(hotstuff_1) try { +/*BOOST_AUTO_TEST_CASE(hotstuff_1) try { test_pacemaker tpm; @@ -330,7 +330,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); -} FC_LOG_AND_RETHROW(); +} FC_LOG_AND_RETHROW();*/ BOOST_AUTO_TEST_CASE(hotstuff_3) try { @@ -349,13 +349,13 @@ ht.print_msg_queue_size(tpm); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + auto qcc_bpc = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpc"_n; }); tpm.set_current_block_id(ids[0]); //first block tpm.beat(); //produce first block and associated proposal tpm.propagate(); //propagate proposal to replicas (prepare on first block) -ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -365,7 +365,6 @@ ht.print_bp_state("bpa"_n, ""); tpm.propagate(); //propagate votes on proposal (prepareQC on first block) tpm.propagate(); //propagate proposal to replicas (precommit on first block) -ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -375,7 +374,6 @@ ht.print_bp_state("bpa"_n, ""); tpm.propagate(); //propagating votes on new proposal (precommitQC on first block) tpm.propagate(); //propagate proposal to replicas (commit on first block) -ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -387,7 +385,6 @@ ht.print_bp_state("bpa"_n, ""); tpm.propagate(); //propagating votes on new proposal (commitQC on first block) tpm.propagate(); //propagate proposal to replicas (decide on first block) -ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -404,7 +401,6 @@ ht.print_bp_state("bpa"_n, ""); tpm.beat(); //produce second block and associated proposal tpm.propagate(); //propagate proposal to replicas (prepare on second block) -ht.print_bp_state("bpb"_n, ""); BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -414,7 +410,6 @@ ht.print_bp_state("bpb"_n, ""); tpm.propagate(); //propagate votes on proposal (prepareQC on second block) tpm.propagate(); //propagate proposal to replicas (precommit on second block) -ht.print_bp_state("bpb"_n, ""); BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); @@ -424,7 +419,6 @@ ht.print_bp_state("bpb"_n, ""); tpm.propagate(); //propagating votes on new proposal (precommitQC on second block) tpm.propagate(); //propagate proposal to replicas (commit on second block) -ht.print_bp_state("bpb"_n, ""); BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); @@ -434,8 +428,6 @@ ht.print_bp_state("bpb"_n, ""); tpm.propagate(); //propagating votes on new proposal (commitQC on second block) tpm.propagate(); //propagate proposal to replicas (decide on second block) -ht.print_bp_state("bpb"_n, ""); -ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); @@ -447,6 +439,13 @@ ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); +ht.print_bp_state("bpc"_n, ""); + + //check bpc as well + BOOST_CHECK_EQUAL(qcc_bpc->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpc->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpc->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_SUITE_END() From 5fe630dc87347d1276bfbb78fab3408a27785e56 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Tue, 28 Mar 2023 16:39:17 +0000 Subject: [PATCH 016/151] Added more unit tests --- .../chain/include/eosio/chain/config.hpp | 2 +- .../include/eosio/hotstuff/test_pacemaker.hpp | 5 +- libraries/hotstuff/qc_chain.cpp | 6 +- libraries/hotstuff/test/test_hotstuff.cpp | 246 +++++++++++++----- libraries/hotstuff/test_pacemaker.cpp | 44 +++- 5 files changed, 229 insertions(+), 74 deletions(-) diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 5f1cbceb80..096bc69f88 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -33,7 +33,7 @@ const static name owner_name { "owner"_n }; const static name eosio_any_name { "eosio.any"_n }; const static name eosio_code_name { "eosio.code"_n }; -const static int block_interval_ms = 5000; +const static int block_interval_ms = 500; const static int block_interval_us = block_interval_ms*1000; const static uint64_t block_timestamp_epoch = 946684800000ll; // epoch is year 2000. const static uint32_t genesis_num_supported_key_types = 2; diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index 76acb8a95a..8f23897185 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -70,7 +70,10 @@ namespace eosio { namespace hotstuff { void add_message_to_queue(hotstuff_message msg); - void propagate(); + std::vector flush(); + + void activate(name replica); + void deactivate(name replica); //indexed_qc_chain get_qc_chain(name replica); diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index cfe18e0c3c..025905b327 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -526,7 +526,11 @@ namespace eosio { namespace hotstuff { _current_qc.quorum_met = true; - //ilog("=== Quorum met on #${block_num} ${proposal_id} ", ("block_num", p_itr->block_num())("proposal_id", vote.proposal_id)); + if (_log) ilog("=== ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", + ("block_num", p_itr->block_num()) + ("phase_counter", p_itr->phase_counter) + ("proposal_id", vote.proposal_id) + ("id", _id)); //ilog("=== update_high_qc : _current_qc ==="); update_high_qc(_current_qc); diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 253ffdf5b9..a8c02d15fe 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -131,7 +131,9 @@ class hotstuff_test_state { BOOST_AUTO_TEST_SUITE(hotstuff) -/*BOOST_AUTO_TEST_CASE(hotstuff_1) try { +BOOST_AUTO_TEST_CASE(hotstuff_1) try { + + //test optimistic responsiveness (3 confirmations per block) test_pacemaker tpm; @@ -151,90 +153,81 @@ BOOST_AUTO_TEST_SUITE(hotstuff) tpm.beat(); //produce first block and associated proposal - tpm.propagate(); //propagate proposal to replicas (prepare on first block) + tpm.flush(); //send proposal to replicas (prepare on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.propagate(); //propagate votes on proposal (prepareQC on first block) + tpm.flush(); //send votes on proposal (prepareQC on first block) - tpm.propagate(); //propagate proposal to replicas (precommit on first block) + tpm.flush(); //send proposal to replicas (precommit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.propagate(); //propagating votes on new proposal (precommitQC on first block) + tpm.flush(); //propagating votes on new proposal (precommitQC on first block) - tpm.propagate(); //propagate proposal to replicas (commit on first block) + tpm.flush(); //send proposal to replicas (commit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.propagate(); //propagating votes on new proposal (commitQC on first block) + tpm.flush(); //propagating votes on new proposal (commitQC on first block) - tpm.propagate(); //propagate proposal to replicas (decide on first block) + tpm.flush(); //send proposal to replicas (decide on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - tpm.propagate(); //propagating votes on new proposal (decide on first block) + tpm.flush(); //propagating votes on new proposal (decide on first block) tpm.set_current_block_id(ids[1]); //second block tpm.beat(); //produce second block and associated proposal - tpm.propagate(); //propagate proposal to replicas (prepare on second block) + tpm.flush(); //send proposal to replicas (prepare on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - tpm.propagate(); //propagate votes on proposal (prepareQC on second block) + tpm.flush(); //send votes on proposal (prepareQC on second block) - tpm.propagate(); //propagate proposal to replicas (precommit on second block) + tpm.flush(); //send proposal to replicas (precommit on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - tpm.propagate(); //propagating votes on new proposal (precommitQC on second block) + tpm.flush(); //propagating votes on new proposal (precommitQC on second block) - tpm.propagate(); //propagate proposal to replicas (commit on second block) + tpm.flush(); //send proposal to replicas (commit on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - tpm.propagate(); //propagating votes on new proposal (commitQC on second block) - - tpm.propagate(); //propagate proposal to replicas (decide on second block) + tpm.flush(); //propagating votes on new proposal (commitQC on second block) -//print_bp_state("bpa"_n, ""); -//print_bp_state("bpb"_n, ""); + tpm.flush(); //send proposal to replicas (decide on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); -//print_msg_queue_size(tpm); - - tpm.propagate(); //propagate proposal to replicas (decide on second block) - -//print_bp_state("bpa"_n, ""); -//print_bp_state("bpb"_n, ""); - + tpm.flush(); //send proposal to replicas (decide on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); @@ -246,11 +239,12 @@ BOOST_AUTO_TEST_SUITE(hotstuff) BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_CASE(hotstuff_2) try { + //test slower network (1 confirmation per block) + test_pacemaker tpm; hotstuff_test_state ht; @@ -269,16 +263,16 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.beat(); //produce first block and associated proposal - tpm.propagate(); //propagate proposal to replicas (prepare on first block) + tpm.flush(); //send proposal to replicas (prepare on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.propagate(); //propagate votes on proposal (prepareQC on first block) + tpm.flush(); //send votes on proposal (prepareQC on first block) - tpm.propagate(); //propagate proposal to replicas (precommit on first block) + tpm.flush(); //send proposal to replicas (precommit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -289,16 +283,16 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.beat(); //produce second block and associated proposal - tpm.propagate(); //propagate proposal to replicas (prepare on second block) + tpm.flush(); //send proposal to replicas (prepare on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.propagate(); //propagate votes on proposal (prepareQC on second block) + tpm.flush(); //send votes on proposal (prepareQC on second block) - tpm.propagate(); //propagate proposal to replicas (precommit on second block) + tpm.flush(); //send proposal to replicas (precommit on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); @@ -309,16 +303,16 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.beat(); //produce third block and associated proposal - tpm.propagate(); //propagating votes on new proposal (precommitQC on third block) + tpm.flush(); //propagating votes on new proposal (prepare on third block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - tpm.propagate(); //propagating votes on new proposal (precommitQC on third block) + tpm.flush(); //send votes on proposal (prepareQC on third block) - tpm.propagate(); //propagating votes on new proposal (precommitQC on third block) + tpm.flush(); //propagating votes on new proposal (precommitQC on third block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); @@ -330,18 +324,18 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); -} FC_LOG_AND_RETHROW();*/ +} FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_CASE(hotstuff_3) try { + //test leader rotation + test_pacemaker tpm; hotstuff_test_state ht; ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, unique_replicas); -ht.print_msg_queue_size(tpm); - tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); tpm.set_next_leader("bpa"_n); @@ -355,79 +349,79 @@ ht.print_msg_queue_size(tpm); tpm.beat(); //produce first block and associated proposal - tpm.propagate(); //propagate proposal to replicas (prepare on first block) + tpm.flush(); //send proposal to replicas (prepare on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.propagate(); //propagate votes on proposal (prepareQC on first block) + tpm.flush(); //send votes on proposal (prepareQC on first block) - tpm.propagate(); //propagate proposal to replicas (precommit on first block) + tpm.flush(); //send proposal to replicas (precommit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.propagate(); //propagating votes on new proposal (precommitQC on first block) + tpm.flush(); //propagating votes on new proposal (precommitQC on first block) - tpm.propagate(); //propagate proposal to replicas (commit on first block) + tpm.flush(); //send proposal to replicas (commit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.set_next_leader("bpb"_n); + tpm.set_next_leader("bpb"_n); //leader is set to rotate on next block - tpm.propagate(); //propagating votes on new proposal (commitQC on first block) + tpm.flush(); //propagating votes on new proposal (commitQC on first block) - tpm.propagate(); //propagate proposal to replicas (decide on first block) + tpm.flush(); //send proposal to replicas (decide on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - tpm.propagate(); //propagating votes on new proposal (decide on first block) + tpm.flush(); //propagating votes on new proposal (decide on first block) - tpm.set_proposer("bpb"_n); + tpm.set_proposer("bpb"_n); //leader has rotated tpm.set_leader("bpb"_n); tpm.set_current_block_id(ids[1]); //second block tpm.beat(); //produce second block and associated proposal - tpm.propagate(); //propagate proposal to replicas (prepare on second block) + tpm.flush(); //send proposal to replicas (prepare on second block) BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - tpm.propagate(); //propagate votes on proposal (prepareQC on second block) + tpm.flush(); //send votes on proposal (prepareQC on second block) - tpm.propagate(); //propagate proposal to replicas (precommit on second block) + tpm.flush(); //send proposal to replicas (precommit on second block) BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - tpm.propagate(); //propagating votes on new proposal (precommitQC on second block) + tpm.flush(); //propagating votes on new proposal (precommitQC on second block) - tpm.propagate(); //propagate proposal to replicas (commit on second block) + tpm.flush(); //send proposal to replicas (commit on second block) BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - tpm.propagate(); //propagating votes on new proposal (commitQC on second block) + tpm.flush(); //propagating votes on new proposal (commitQC on second block) - tpm.propagate(); //propagate proposal to replicas (decide on second block) + tpm.flush(); //send proposal to replicas (decide on second block) BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); @@ -439,8 +433,6 @@ ht.print_msg_queue_size(tpm); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); -ht.print_bp_state("bpc"_n, ""); - //check bpc as well BOOST_CHECK_EQUAL(qcc_bpc->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(qcc_bpc->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); @@ -448,4 +440,142 @@ ht.print_bp_state("bpc"_n, ""); } FC_LOG_AND_RETHROW(); +BOOST_AUTO_TEST_CASE(hotstuff_4) try { + + //test loss and recovery of liveness on new block + + test_pacemaker tpm; + + hotstuff_test_state ht; + + ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, unique_replicas); + + tpm.set_proposer("bpa"_n); + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); + + auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + auto qcc_bpi = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpi"_n; }); + + tpm.set_current_block_id(ids[0]); //first block + + tpm.beat(); //produce first block and associated proposal + + tpm.flush(); //send proposal to replicas (prepare on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.flush(); //send votes on proposal (prepareQC on first block) + + tpm.flush(); //send proposal to replicas (precommit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.flush(); //propagating votes on new proposal (precommitQC on first block) + +ht.print_bp_state("bpa"_n, "before deactivate"); + + tpm.deactivate("bpb"_n); //loss of liveness as 7 finalizers out of 21 go offline + tpm.deactivate("bpc"_n); + tpm.deactivate("bpd"_n); + tpm.deactivate("bpe"_n); + tpm.deactivate("bpf"_n); + tpm.deactivate("bpg"_n); + tpm.deactivate("bph"_n); + + tpm.flush(); //send proposal to replicas (commit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.set_next_leader("bpi"_n); //leader is set to rotate on next block + + tpm.flush(); //propagating votes on new proposal (insufficient to reach quorum) + +ht.print_bp_state("bpa"_n, "before reactivate"); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.activate("bpb"_n); + tpm.activate("bpc"_n); + tpm.activate("bpd"_n); + tpm.activate("bpe"_n); + tpm.activate("bpf"_n); + tpm.activate("bpg"_n); + tpm.activate("bph"_n); + + tpm.set_proposer("bpi"_n); + tpm.set_leader("bpi"_n); + + tpm.set_current_block_id(ids[1]); //second block + + tpm.beat(); //produce second block and associated proposal + + tpm.flush(); //send proposal to replicas (prepare on second block) + +ht.print_bp_state("bpi"_n, ""); + +ht.print_bp_state("bpa"_n, ""); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.flush(); //send votes on proposal (prepareQC on second block) + + tpm.flush(); //send proposal to replicas (precommit on second block) + +ht.print_bp_state("bpa"_n, ""); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.flush(); //propagating votes on new proposal (precommitQC on second block) + + tpm.flush(); //send proposal to replicas (commit on second block) + +ht.print_bp_state("bpa"_n, ""); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + + tpm.flush(); //propagating votes on new proposal (commitQC on second block) + + tpm.flush(); //send proposal to replicas (decide on second block) + +ht.print_bp_state("bpa"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + +ht.print_bp_state("bpb"_n, ""); + //check bpa as well + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + +ht.print_bp_state("bpi"_n, ""); + BOOST_CHECK_EQUAL(qcc_bpi->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpi->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpi->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + +} FC_LOG_AND_RETHROW(); + BOOST_AUTO_TEST_SUITE_END() diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test_pacemaker.cpp index 24824bf3fd..4b7ba2e9ec 100644 --- a/libraries/hotstuff/test_pacemaker.cpp +++ b/libraries/hotstuff/test_pacemaker.cpp @@ -45,12 +45,13 @@ namespace eosio { namespace hotstuff { _pending_message_queue.push_back(msg); } - void test_pacemaker::propagate(){ + std::vector test_pacemaker::flush(){ int count = 1; //ilog(" === propagate ${count} messages", ("count", _pending_message_queue.size())); + std::vector flushed_messages = _pending_message_queue; _message_queue = _pending_message_queue; while (_pending_message_queue.begin()!=_pending_message_queue.end()){ @@ -99,6 +100,31 @@ namespace eosio { namespace hotstuff { //ilog(" === end propagate"); + return _pending_message_queue; + + } + + void test_pacemaker::activate(name replica){ + + auto qc_itr = _qcc_store.get().find( replica.to_uint64_t() ); + + if (qc_itr==_qcc_store.end()) throw std::runtime_error("replica not found"); + + _qcc_store.modify(qc_itr, [&]( auto& qcc ){ + qcc._active = true; + }); + } + + void test_pacemaker::deactivate(name replica){ + + auto qc_itr = _qcc_store.get().find( replica.to_uint64_t() ); + + if (qc_itr==_qcc_store.end()) throw std::runtime_error("replica not found"); + + _qcc_store.modify(qc_itr, [&]( auto& qcc ){ + qcc._active = false; + }); + } name test_pacemaker::get_proposer(){ @@ -145,10 +171,6 @@ namespace eosio { namespace hotstuff { if (itr!=_qcc_store.end()){ - _qcc_store.modify(itr, [&]( auto& qcc ){ - qcc._active = true; - }); - throw std::runtime_error("duplicate qc chain"); } @@ -166,9 +188,7 @@ namespace eosio { namespace hotstuff { //ilog(" === register_listener 1 ${my_producers}", ("my_producers", iqcc._qc_chain->_my_producers)); - _qcc_store.insert(iqcc); - - //ilog("aaadddd"); + _qcc_store.insert(iqcc); //auto itr = _qcc_store.get().find( name.to_uint64_t() ); @@ -185,11 +205,9 @@ namespace eosio { namespace hotstuff { auto itr = _qcc_store.get().find( name.to_uint64_t() ); if (itr!= _qcc_store.end()) { - - _qcc_store.modify(itr, [&]( auto& qcc ){ - qcc._active = false; - }); - + + _qcc_store.erase(itr); + } else throw std::runtime_error("qc chain not found"); From 14ba4b1e5c75d1e603e407850c737a68e815f562 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sat, 1 Apr 2023 13:40:25 +0000 Subject: [PATCH 017/151] Completed finality violation unit test, improved logging --- .../chain/include/eosio/chain/hotstuff.hpp | 14 - .../include/eosio/hotstuff/base_pacemaker.hpp | 31 +- .../include/eosio/hotstuff/qc_chain.hpp | 7 +- .../include/eosio/hotstuff/test_pacemaker.hpp | 5 +- libraries/hotstuff/qc_chain.cpp | 209 +++++---- libraries/hotstuff/test/test_hotstuff.cpp | 405 ++++++++++++++---- libraries/hotstuff/test_pacemaker.cpp | 63 ++- plugins/producer_plugin/producer_plugin.cpp | 2 +- 8 files changed, 491 insertions(+), 245 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index cba1c5ef48..5aa7f43b83 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -13,15 +13,6 @@ namespace eosio { namespace chain { const block_id_type NULL_BLOCK_ID = block_id_type("00"); const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - //using namespace fc::crypto::blslib; - - //todo : fetch from chain / nodeos config - -/* const uint32_t block_interval = 500; - const uint32_t blocks_per_round = 12;*/ - - - static uint32_t compute_block_num(block_id_type block_id) { return fc::endian_reverse_u32(block_id._hash[0]); @@ -61,10 +52,6 @@ namespace eosio { namespace chain { hs_vote_message() = default; -/* uint32_t block_num()const{ - return compute_block_num(block_id); - }*/ - }; struct hs_proposal_message { @@ -117,7 +104,6 @@ namespace eosio { namespace chain { }} //eosio::chain - FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(phase_counter)(parent_id)(final_on_qc)(justify)); diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index eba0069195..c864b6c53f 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -16,42 +16,25 @@ namespace eosio { namespace hotstuff { public: - - //configuration setting + //todo : discuss virtual uint32_t get_quorum_threshold() = 0; - - - //polling calls + virtual block_id_type get_current_block_id() = 0; + + //hotstuff getters. todo : implement relevant setters as host functions virtual name get_proposer() = 0; virtual name get_leader() = 0; virtual name get_next_leader() = 0; virtual std::vector get_finalizers() = 0; - virtual block_id_type get_current_block_id() = 0; - - - - - - - - - + //block / proposal API + virtual void beat() = 0; + //todo : abstract further //qc_chain event subscription virtual void register_listener(name name, qc_chain& qcc) = 0; virtual void unregister_listener(name name) = 0; - - - - //block / proposal API - virtual void beat() = 0; - - - - //outbound communications virtual void send_hs_proposal_msg(name id, hs_proposal_message msg) = 0; virtual void send_hs_vote_msg(name id, hs_vote_message msg) = 0; diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 8eece66ec7..0050c7030c 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -65,6 +65,8 @@ namespace eosio { namespace hotstuff { fc::sha256 _b_leaf = NULL_PROPOSAL_ID; fc::sha256 _b_lock = NULL_PROPOSAL_ID; fc::sha256 _b_exec = NULL_PROPOSAL_ID; + + fc::sha256 _b_finality_violation = NULL_PROPOSAL_ID; block_id_type _block_exec = NULL_BLOCK_ID; @@ -73,6 +75,7 @@ namespace eosio { namespace hotstuff { uint32_t _v_height; bool _log = true; + bool _errors = true; eosio::chain::quorum_certificate _high_qc; eosio::chain::quorum_certificate _current_qc; @@ -93,7 +96,7 @@ namespace eosio { namespace hotstuff { tag, BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) >, - ordered_unique< + ordered_non_unique< tag, BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) > @@ -119,7 +122,7 @@ namespace eosio { namespace hotstuff { hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); //create new proposal message hs_new_block_message new_block_candidate(block_id_type block_id); //create new block message - void init(name id, base_pacemaker& pacemaker, std::set my_producers, bool logging_enabled); //initialize qc object and add reference to the pacemaker + void init(name id, base_pacemaker& pacemaker, std::set my_producers, bool info_logging, bool error_logging); //initialize qc object and add reference to the pacemaker bool am_i_proposer(); //check if I am the current proposer bool am_i_leader(); //check if I am the current leader diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index 8f23897185..12b4afd9a2 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -70,7 +70,10 @@ namespace eosio { namespace hotstuff { void add_message_to_queue(hotstuff_message msg); - std::vector flush(); + void pipe(std::vector messages); + + std::vector dispatch(std::string memo, int count); + std::vector dispatch(std::string memo); void activate(name replica); void deactivate(name replica); diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 025905b327..3a3aa18f5f 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -238,10 +238,11 @@ namespace eosio { namespace hotstuff { } - void qc_chain::init(name id, base_pacemaker& pacemaker, std::set my_producers, bool logging_enabled){ + void qc_chain::init(name id, base_pacemaker& pacemaker, std::set my_producers, bool info_logging, bool error_logging){ _id = id; - _log = logging_enabled; + _log = info_logging; + _errors = error_logging; _pacemaker = &pacemaker; @@ -251,8 +252,6 @@ namespace eosio { namespace hotstuff { if (_log) ilog(" === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); - //auto itr = _my_producers.begin(); - //ilog("bla"); //ilog("name ${name}", ("name", *itr)); @@ -321,15 +320,10 @@ namespace eosio { namespace hotstuff { _v_height = proposal.get_height(); - //fc::crypto::blslib::bls_signature agg_sig; - - //if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); std::vector h = std::vector(digest.data(), digest.data() + 32); - fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer hs_vote_message v_msg = {proposal.proposal_id, finalizer, sig}; @@ -338,55 +332,63 @@ namespace eosio { namespace hotstuff { //ilog("signed proposal. Broadcasting for each of my producers"); -/* auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - auto prod_itr = std::find(finalizers.begin(), finalizers.end(), *mf_itr); + } - if (prod_itr!=finalizers.end()) { + void qc_chain::process_proposal(hs_proposal_message proposal){ - fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer + auto start = fc::time_point::now(); - name n = *prod_itr; + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID){ - hs_vote_message v_msg = {proposal.proposal_id, n, sig}; + auto jp_itr = _proposal_store.get().find( proposal.justify.proposal_id ); - send_hs_vote_msg(v_msg); + if (jp_itr == _proposal_store.get().end()) { + if (_errors) ilog("*** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); + return; //can't recognize a proposal with an unknown justification + } - }; + } - mf_itr++; + auto pid_itr = _proposal_store.get().find( proposal.proposal_id ); - }*/ + if (pid_itr != _proposal_store.get().end()) { - } + if (_errors) ilog(" *** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); - void qc_chain::process_proposal(hs_proposal_message proposal){ + if (pid_itr->justify.proposal_id != proposal.justify.proposal_id) { - auto start = fc::time_point::now(); + if (_errors) ilog(" *** ${id} two identical proposals (${proposal_id}) have different justifications : ${justify_1} vs ${justify_2}", + ("id",_id) + ("proposal_id", proposal.proposal_id) + ("justify_1", pid_itr->justify.proposal_id) + ("justify_2", proposal.justify.proposal_id)); - auto pid_itr = _proposal_store.get().find( proposal.proposal_id ); + } - if (pid_itr != _proposal_store.get().end()) { - ilog("*** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); return ; //already aware of proposal, nothing to do } - auto hgt_itr = _proposal_store.get().find( proposal.get_height() ); + auto hgt_itr = _proposal_store.get().lower_bound( proposal.get_height() ); + auto end_itr = _proposal_store.get().upper_bound( proposal.get_height() ); - if (hgt_itr != _proposal_store.get().end()) { - ilog("*** ${id} received two different proposals at the same height (${block_num}, ${phase_counter}) : Proposal #1 : ${proposal_id_1} Proposal #2 : ${proposal_id_2}", + //height is not necessarily unique, so we iterate over all prior proposals at this height + while (hgt_itr != end_itr) { + if (_errors) ilog(" *** ${id} received a different proposal at the same height (${block_num}, ${phase_counter})", ("id",_id) ("block_num", hgt_itr->block_num()) - ("phase_counter", hgt_itr->phase_counter) + ("phase_counter", hgt_itr->phase_counter)); + + if (_errors) ilog(" *** Proposal #1 : ${proposal_id_1} Proposal #2 : ${proposal_id_2}", ("proposal_id_1", hgt_itr->proposal_id) ("proposal_id_2", proposal.proposal_id)); + hgt_itr++; + } - if (_log) ilog("=== ${id} received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", + + if (_log) ilog(" === ${id} received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) @@ -417,44 +419,11 @@ namespace eosio { namespace hotstuff { hs_vote_message v_msg = sign_proposal(proposal, *prod_itr); - send_hs_vote_msg(v_msg); - - }; - - mf_itr++; - - } - - /* //ilog("signature required"); - - _v_height = proposal.get_height(); - - fc::crypto::blslib::bls_signature agg_sig; - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; - - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - //iterate over all my finalizers and sign / broadcast for each that is in the schedule - std::vector finalizers = _pacemaker->get_finalizers(); - - //ilog("signed proposal. Broadcasting for each of my producers"); - - auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - auto prod_itr = std::find(finalizers.begin(), finalizers.end(), *mf_itr); - - if (prod_itr!=finalizers.end()) { - - fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer - - name n = *prod_itr; - - hs_vote_message v_msg = {proposal.proposal_id, n, sig}; + if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id)); send_hs_vote_msg(v_msg); @@ -463,12 +432,13 @@ namespace eosio { namespace hotstuff { mf_itr++; } -*/ } - - - + else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id)); //update internal state @@ -504,9 +474,9 @@ namespace eosio { namespace hotstuff { proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); if (p_itr==_proposal_store.get().end()){ - ilog("*** ${id} couldn't find proposal", ("id",_id)); + if (_errors) ilog("*** ${id} couldn't find proposal", ("id",_id)); - ilog("*** ${id} vote : ${vote}", ("vote", vote)("id",_id)); + if (_errors) ilog("*** ${id} vote : ${vote}", ("vote", vote)("id",_id)); return; } @@ -644,7 +614,7 @@ namespace eosio { namespace hotstuff { if (itr->proposal_id == ancestor){ if (counter>25) { - ilog("*** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); + if (_errors) ilog("*** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); } return true; @@ -654,7 +624,7 @@ namespace eosio { namespace hotstuff { } - ilog(" *** ${id} extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", + if (_errors) ilog(" *** ${id} extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", ("id",_id) ("d_proposal_id", descendant) ("a_proposal_id", ancestor)); @@ -941,6 +911,18 @@ handle_eptr(eptr); ("liveness_check", liveness_check) ("safety_check", safety_check));*/ + bool node_is_safe = final_on_qc_check && monotony_check && (liveness_check || safety_check); + + if (!node_is_safe) { + + if (_errors) ilog(" *** node is NOT safe. Checks : final_on_qc: ${final_on_qc}, monotony_check: ${monotony_check}, liveness_check: ${liveness_check}, safety_check: ${safety_check})", + ("final_on_qc_check",final_on_qc_check) + ("monotony_check",monotony_check) + ("liveness_check",liveness_check) + ("safety_check",safety_check)); + + } + return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully } @@ -959,7 +941,7 @@ try{ //ilog(" === end of on_hs_proposal_msg"); } catch (...){ - ilog(" *** ${id} error during on_hs_proposal_msg", ("id",_id)); + if (_errors) ilog(" *** ${id} error during on_hs_proposal_msg", ("id",_id)); eptr = std::current_exception(); // capture } handle_eptr(eptr); @@ -979,7 +961,7 @@ try{ //ilog(" === end of on_hs_vote_msg"); } catch (...){ - ilog(" *** ${id} error during on_hs_vote_msg", ("id",_id)); + if (_errors) ilog(" *** ${id} error during on_hs_vote_msg", ("id",_id)); eptr = std::current_exception(); // capture } handle_eptr(eptr); @@ -999,7 +981,7 @@ try{ //ilog(" === end of on_hs_new_view_msg"); } catch (...){ - ilog(" *** ${id} error during on_hs_new_view_msg", ("id",_id)); + if (_errors) ilog(" *** ${id} error during on_hs_new_view_msg", ("id",_id)); eptr = std::current_exception(); // capture } handle_eptr(eptr); @@ -1019,7 +1001,7 @@ try{ //ilog(" === end of on_hs_new_block_msg"); } catch (...){ - ilog(" *** ${id} error during on_hs_new_block_msg", ("id",_id)); + if (_errors) ilog(" *** ${id} error during on_hs_new_block_msg", ("id",_id)); eptr = std::current_exception(); // capture } handle_eptr(eptr); @@ -1029,8 +1011,6 @@ handle_eptr(eptr); //ilog("=== update internal state ==="); - proposal_store_type::nth_index<0>::type::iterator b_lock; - //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ if (_log) ilog(" === ${id} proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)("id", _id)); @@ -1041,7 +1021,7 @@ handle_eptr(eptr); size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - b_lock = _proposal_store.get().find( _b_lock); + proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock); //ilog("=== update_high_qc : proposal.justify ==="); update_high_qc(proposal.justify); @@ -1102,6 +1082,28 @@ handle_eptr(eptr); //ilog("direct parent relationship verified"); + if (_b_exec!= NULL_PROPOSAL_ID){ + + proposal_store_type::nth_index<0>::type::iterator b_exec = _proposal_store.get().find( _b_exec); + + if (b_exec->get_height() >= b.get_height() && b_exec->proposal_id != b.proposal_id){ + + if (_errors) ilog(" *** ${id} finality violation detected at height ${block_num}, phase : ${phase}. Proposal ${proposal_id_1} conflicts with ${proposal_id_2}", + ("id", _id) + ("block_num", b.block_num()) + ("phase", b.phase_counter) + ("proposal_id_1", b.proposal_id) + ("proposal_id_2", b_exec->proposal_id)); + + _b_finality_violation = b.proposal_id; + + //protocol failure + + return; + + } + + } commit(b); @@ -1118,11 +1120,11 @@ handle_eptr(eptr); } else { - ilog(" *** ${id} could not verify direct parent relationship", ("id",_id)); + if (_errors) ilog(" *** ${id} could not verify direct parent relationship", ("id",_id)); - ilog(" *** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); - ilog(" *** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); - ilog(" *** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); + if (_errors) ilog(" *** b_2 ${b_2}", ("b_2", b_2)); + if (_errors) ilog(" *** b_1 ${b_1}", ("b_1", b_1)); + if (_errors) ilog(" *** b ${b}", ("b", b)); } @@ -1162,7 +1164,7 @@ handle_eptr(eptr); ("phase_counter", proposal.phase_counter) ("parent_id", proposal.parent_id)); */ - bool sequence_respected = false; + bool exec_height_check = false; proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); @@ -1173,13 +1175,19 @@ handle_eptr(eptr); ("phase_counter", last_exec_prop->phase_counter) ("parent_id", last_exec_prop->parent_id));*/ +/* ilog(" *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", + ("proposal_id_1", last_exec_prop->block_num()) + ("phase_counter_1", last_exec_prop->phase_counter) + ("proposal_id_2", proposal.block_num()) + ("phase_counter_2", proposal.phase_counter));*/ + if (_b_exec==NULL_PROPOSAL_ID){ //ilog("first block committed"); - sequence_respected = true; + exec_height_check = true; } - else sequence_respected = last_exec_prop->get_height() < proposal.get_height(); + else exec_height_check = last_exec_prop->get_height() < proposal.get_height(); - if (sequence_respected){ + if (exec_height_check){ proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); @@ -1191,15 +1199,26 @@ handle_eptr(eptr); } + //Execute commands [...] + if (_log) ilog(" === ${id} committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) ("block_id", proposal.block_id) ("proposal_id", proposal.proposal_id)); - } + +/* else { + if (_errors) ilog(" *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id)); + }*/ + + } }} diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index a8c02d15fe..4400861372 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -16,32 +16,33 @@ using std::cout; std::vector ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c39"), block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530684"), - block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf330"), - block_id_type("00000004235f391d91d5da938cfa8c4738d92da6c007da596f1db05c37d38866"), - block_id_type("00000005485fa018c16b6150aed839bdd4cbc2149f70191e89f2b19fe711b1c0"), - block_id_type("00000006161b9c79797059bbdcbf49614bbdca33d35b8099ffa250583dc41d9d"), - block_id_type("00000007ffd04a602236843f842827c2ac2aa61d586b7ebc8cc3c276921b55d9"), - block_id_type("000000085e8b9b158801fea3f7b2b627734805b9192568b67d7d00d676e427e3"), - block_id_type("0000000979b05f273f2885304f952aaa6f47d56985e003ec35c22472682ad3a2"), - block_id_type("0000000a703d6a104c722b8bc2d7227b90a35d08835343564c2fd66eb9dcf999"), - block_id_type("0000000ba7ef2e432d465800e53d1da982f2816c051153f9054960089d2f37d8") }; + block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf330")}; + + +std::vector alternate_ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c31"), + block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530681"), + block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf331")}; + //list of unique replicas for our test std::vector unique_replicas{ "bpa"_n, "bpb"_n, "bpc"_n, "bpd"_n, "bpe"_n, "bpf"_n, "bpg"_n, "bph"_n, "bpi"_n, - "bpj"_n, "bpk"_n ,"bpl"_n, + "bpj"_n, "bpk"_n, "bpl"_n, "bpm"_n, "bpn"_n, "bpo"_n, "bpp"_n, "bpq"_n, "bpr"_n, "bps"_n, "bpt"_n, "bpu"_n }; -class hotstuff_test_state { + + + +class hotstuff_test_handler { public: std::vector> _qc_chains; - void initialize_qc_chains(test_pacemaker& tpm, std::vector loggers, std::vector replicas){ + void initialize_qc_chains(test_pacemaker& tpm, std::vector info_loggers, std::vector error_loggers, std::vector replicas){ _qc_chains.clear(); @@ -58,12 +59,15 @@ class hotstuff_test_state { while (itr!=_qc_chains.end()){ bool log = false; + bool err = false; - auto found = std::find(loggers.begin(), loggers.end(), replicas[counter]); + auto i_found = std::find(info_loggers.begin(), info_loggers.end(), replicas[counter]); + auto e_found = std::find(error_loggers.begin(), error_loggers.end(), replicas[counter]); - if (found!=loggers.end()) log = true; + if (i_found!=info_loggers.end()) log = true; + if (e_found!=error_loggers.end()) err = true; - itr->second.init(replicas[counter], tpm, {replicas[counter]}, log); + itr->second.init(replicas[counter], tpm, {replicas[counter]}, log, err); itr++; counter++; @@ -72,26 +76,53 @@ class hotstuff_test_state { } - void print_msg_queue_size(test_pacemaker &tpm){ + void print_msgs(std::vector msgs ){ + + size_t proposals_count = 0; + size_t votes_count = 0; + size_t new_blocks_count = 0; + size_t new_views_count = 0; + + auto msg_itr = msgs.begin(); + + while (msg_itr!=msgs.end()){ + + size_t v_index = msg_itr->second.index(); + + if(v_index==0) proposals_count++; + if(v_index==1) votes_count++; + if(v_index==2) new_blocks_count++; + if(v_index==3) new_views_count++; + + msg_itr++; + + } std::cout << "\n"; - std::cout << " message queue size : " << tpm._pending_message_queue.size() << "\n"; + std::cout << " message queue size : " << msgs.size() << "\n"; + std::cout << " proposals : " << proposals_count << "\n"; + std::cout << " votes : " << votes_count << "\n"; + std::cout << " new_blocks : " << new_blocks_count << "\n"; + std::cout << " new_views : " << new_views_count << "\n"; std::cout << "\n"; } + void print_msg_queue(test_pacemaker &tpm){ + + print_msgs(tpm._pending_message_queue); + + } + void print_pm_state(test_pacemaker &tpm){ std::cout << "\n"; std::cout << " leader : " << tpm.get_leader() << "\n"; - std::cout << " next leader : " << tpm.get_next_leader() << "\n"; - std::cout << " proposer : " << tpm.get_proposer() << "\n"; - std::cout << " current block id : " << tpm.get_current_block_id().str() << "\n"; std::cout << "\n"; @@ -137,9 +168,9 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { test_pacemaker tpm; - hotstuff_test_state ht; + hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n}, unique_replicas); + ht.initialize_qc_chains(tpm, {"bpa"_n}, {"bpa"_n}, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); @@ -153,81 +184,81 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { tpm.beat(); //produce first block and associated proposal - tpm.flush(); //send proposal to replicas (prepare on first block) + tpm.dispatch(""); //send proposal to replicas (prepare on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //send votes on proposal (prepareQC on first block) + tpm.dispatch(""); //send votes on proposal (prepareQC on first block) - tpm.flush(); //send proposal to replicas (precommit on first block) + tpm.dispatch(""); //send proposal to replicas (precommit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //propagating votes on new proposal (precommitQC on first block) + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) - tpm.flush(); //send proposal to replicas (commit on first block) + tpm.dispatch(""); //send proposal to replicas (commit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //propagating votes on new proposal (commitQC on first block) + tpm.dispatch(""); //propagating votes on new proposal (commitQC on first block) - tpm.flush(); //send proposal to replicas (decide on first block) + tpm.dispatch(""); //send proposal to replicas (decide on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - tpm.flush(); //propagating votes on new proposal (decide on first block) + tpm.dispatch(""); //propagating votes on new proposal (decide on first block) tpm.set_current_block_id(ids[1]); //second block tpm.beat(); //produce second block and associated proposal - tpm.flush(); //send proposal to replicas (prepare on second block) + tpm.dispatch(""); //send proposal to replicas (prepare on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - tpm.flush(); //send votes on proposal (prepareQC on second block) + tpm.dispatch(""); //send votes on proposal (prepareQC on second block) - tpm.flush(); //send proposal to replicas (precommit on second block) + tpm.dispatch(""); //send proposal to replicas (precommit on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - tpm.flush(); //propagating votes on new proposal (precommitQC on second block) + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) - tpm.flush(); //send proposal to replicas (commit on second block) + tpm.dispatch(""); //send proposal to replicas (commit on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - tpm.flush(); //propagating votes on new proposal (commitQC on second block) + tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) - tpm.flush(); //send proposal to replicas (decide on second block) + tpm.dispatch(""); //send proposal to replicas (decide on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - tpm.flush(); //send proposal to replicas (decide on second block) + tpm.dispatch(""); //send proposal to replicas (decide on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); @@ -239,6 +270,8 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_CASE(hotstuff_2) try { @@ -247,9 +280,9 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { test_pacemaker tpm; - hotstuff_test_state ht; + hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n}, unique_replicas); + ht.initialize_qc_chains(tpm, {"bpa"_n}, {"bpa"_n}, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); @@ -263,16 +296,16 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.beat(); //produce first block and associated proposal - tpm.flush(); //send proposal to replicas (prepare on first block) + tpm.dispatch(""); //send proposal to replicas (prepare on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //send votes on proposal (prepareQC on first block) + tpm.dispatch(""); //send votes on proposal (prepareQC on first block) - tpm.flush(); //send proposal to replicas (precommit on first block) + tpm.dispatch(""); //send proposal to replicas (precommit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -283,16 +316,16 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.beat(); //produce second block and associated proposal - tpm.flush(); //send proposal to replicas (prepare on second block) + tpm.dispatch(""); //send proposal to replicas (prepare on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //send votes on proposal (prepareQC on second block) + tpm.dispatch(""); //send votes on proposal (prepareQC on second block) - tpm.flush(); //send proposal to replicas (precommit on second block) + tpm.dispatch(""); //send proposal to replicas (precommit on second block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); @@ -303,16 +336,16 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.beat(); //produce third block and associated proposal - tpm.flush(); //propagating votes on new proposal (prepare on third block) + tpm.dispatch(""); //propagating votes on new proposal (prepare on third block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - tpm.flush(); //send votes on proposal (prepareQC on third block) + tpm.dispatch(""); //send votes on proposal (prepareQC on third block) - tpm.flush(); //propagating votes on new proposal (precommitQC on third block) + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on third block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); @@ -324,6 +357,8 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_CASE(hotstuff_3) try { @@ -332,9 +367,9 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { test_pacemaker tpm; - hotstuff_test_state ht; + hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, unique_replicas); + ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n},unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); @@ -349,25 +384,25 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.beat(); //produce first block and associated proposal - tpm.flush(); //send proposal to replicas (prepare on first block) + tpm.dispatch(""); //send proposal to replicas (prepare on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //send votes on proposal (prepareQC on first block) + tpm.dispatch(""); //send votes on proposal (prepareQC on first block) - tpm.flush(); //send proposal to replicas (precommit on first block) + tpm.dispatch(""); //send proposal to replicas (precommit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //propagating votes on new proposal (precommitQC on first block) + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) - tpm.flush(); //send proposal to replicas (commit on first block) + tpm.dispatch(""); //send proposal to replicas (commit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -376,16 +411,16 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.set_next_leader("bpb"_n); //leader is set to rotate on next block - tpm.flush(); //propagating votes on new proposal (commitQC on first block) + tpm.dispatch(""); //propagating votes on new proposal (commitQC on first block) - tpm.flush(); //send proposal to replicas (decide on first block) + tpm.dispatch(""); //send proposal to replicas (decide on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - tpm.flush(); //propagating votes on new proposal (decide on first block) + tpm.dispatch(""); //propagating votes on new proposal (decide on first block) tpm.set_proposer("bpb"_n); //leader has rotated tpm.set_leader("bpb"_n); @@ -394,34 +429,34 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.beat(); //produce second block and associated proposal - tpm.flush(); //send proposal to replicas (prepare on second block) + tpm.dispatch(""); //send proposal to replicas (prepare on second block) BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - tpm.flush(); //send votes on proposal (prepareQC on second block) + tpm.dispatch(""); //send votes on proposal (prepareQC on second block) - tpm.flush(); //send proposal to replicas (precommit on second block) + tpm.dispatch(""); //send proposal to replicas (precommit on second block) BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - tpm.flush(); //propagating votes on new proposal (precommitQC on second block) + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) - tpm.flush(); //send proposal to replicas (commit on second block) + tpm.dispatch(""); //send proposal to replicas (commit on second block) BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - tpm.flush(); //propagating votes on new proposal (commitQC on second block) + tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) - tpm.flush(); //send proposal to replicas (decide on second block) + tpm.dispatch(""); //send proposal to replicas (decide on second block) BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); @@ -438,6 +473,8 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { BOOST_CHECK_EQUAL(qcc_bpc->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(qcc_bpc->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_CASE(hotstuff_4) try { @@ -446,9 +483,9 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { test_pacemaker tpm; - hotstuff_test_state ht; + hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, unique_replicas); + ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n}, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); @@ -463,25 +500,25 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { tpm.beat(); //produce first block and associated proposal - tpm.flush(); //send proposal to replicas (prepare on first block) + tpm.dispatch(""); //send proposal to replicas (prepare on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //send votes on proposal (prepareQC on first block) + tpm.dispatch(""); //send votes on proposal (prepareQC on first block) - tpm.flush(); //send proposal to replicas (precommit on first block) + tpm.dispatch(""); //send proposal to replicas (precommit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //propagating votes on new proposal (precommitQC on first block) + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) -ht.print_bp_state("bpa"_n, "before deactivate"); +//ht.print_bp_state("bpa"_n, "before deactivate"); tpm.deactivate("bpb"_n); //loss of liveness as 7 finalizers out of 21 go offline tpm.deactivate("bpc"_n); @@ -491,7 +528,7 @@ ht.print_bp_state("bpa"_n, "before deactivate"); tpm.deactivate("bpg"_n); tpm.deactivate("bph"_n); - tpm.flush(); //send proposal to replicas (commit on first block) + tpm.dispatch(""); //send proposal to replicas (commit on first block) BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -500,9 +537,9 @@ ht.print_bp_state("bpa"_n, "before deactivate"); tpm.set_next_leader("bpi"_n); //leader is set to rotate on next block - tpm.flush(); //propagating votes on new proposal (insufficient to reach quorum) + tpm.dispatch(""); //propagating votes on new proposal (insufficient to reach quorum) -ht.print_bp_state("bpa"_n, "before reactivate"); +//ht.print_bp_state("bpa"_n, "before reactivate"); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -524,58 +561,246 @@ ht.print_bp_state("bpa"_n, "before reactivate"); tpm.beat(); //produce second block and associated proposal - tpm.flush(); //send proposal to replicas (prepare on second block) + tpm.dispatch(""); //send proposal to replicas (prepare on second block) -ht.print_bp_state("bpi"_n, ""); +//ht.print_bp_state("bpi"_n, ""); -ht.print_bp_state("bpa"_n, ""); +//ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - tpm.flush(); //send votes on proposal (prepareQC on second block) + tpm.dispatch(""); //send votes on proposal (prepareQC on second block) - tpm.flush(); //send proposal to replicas (precommit on second block) + tpm.dispatch(""); //send proposal to replicas (precommit on second block) -ht.print_bp_state("bpa"_n, ""); +//ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - tpm.flush(); //propagating votes on new proposal (precommitQC on second block) + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) - tpm.flush(); //send proposal to replicas (commit on second block) + tpm.dispatch(""); //send proposal to replicas (commit on second block) -ht.print_bp_state("bpa"_n, ""); +//ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - tpm.flush(); //propagating votes on new proposal (commitQC on second block) + tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) - tpm.flush(); //send proposal to replicas (decide on second block) + tpm.dispatch(""); //send proposal to replicas (decide on second block) -ht.print_bp_state("bpa"_n, ""); +//ht.print_bp_state("bpa"_n, ""); BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); -ht.print_bp_state("bpb"_n, ""); +//ht.print_bp_state("bpb"_n, ""); //check bpa as well BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); -ht.print_bp_state("bpi"_n, ""); +//ht.print_bp_state("bpi"_n, ""); BOOST_CHECK_EQUAL(qcc_bpi->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(qcc_bpi->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(qcc_bpi->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_5) try { + + //test finality violation + + std::vector honest_replica_set_1 { "bpb"_n, + "bpe"_n, + "bph"_n, + "bpk"_n, + "bpn"_n, + "bpq"_n }; + + std::vector honest_replica_set_2 { "bpa"_n, + "bpd"_n, + "bpg"_n, + "bpj"_n, + "bpm"_n, + "bpp"_n }; + + std::vector byzantine_set { "bpc"_n, + "bpf"_n, + "bpi"_n, + "bpl"_n, + "bpo"_n, + "bpr"_n, + "bpu"_n, + "bps"_n, + "bpt"_n }; + + std::vector replica_set_1; + std::vector replica_set_2; + + replica_set_1.reserve( honest_replica_set_1.size() + byzantine_set.size() ); + replica_set_2.reserve( honest_replica_set_2.size() + byzantine_set.size() ); + + replica_set_1.insert( replica_set_1.end(), honest_replica_set_1.begin(), honest_replica_set_1.end() ); + replica_set_1.insert( replica_set_1.end(), byzantine_set.begin(), byzantine_set.end() ); + + replica_set_2.insert( replica_set_2.end(), honest_replica_set_2.begin(), honest_replica_set_2.end() ); + replica_set_2.insert( replica_set_2.end(), byzantine_set.begin(), byzantine_set.end() ); + + //simulating a fork, where + test_pacemaker tpm1; + test_pacemaker tpm2; + + hotstuff_test_handler ht1; + hotstuff_test_handler ht2; + + ht1.initialize_qc_chains(tpm1, {"bpe"_n}, {"bpe"_n}, replica_set_1); + + ht2.initialize_qc_chains(tpm2, {}, {}, replica_set_2); + + tpm1.set_proposer("bpe"_n); //honest leader + tpm1.set_leader("bpe"_n); + tpm1.set_next_leader("bpe"_n); + tpm1.set_finalizers(replica_set_1); + + tpm2.set_proposer("bpf"_n); //byzantine leader + tpm2.set_leader("bpf"_n); + tpm2.set_next_leader("bpf"_n); + tpm2.set_finalizers(replica_set_2); + + auto qcc_bpe = std::find_if(ht1._qc_chains.begin(), ht1._qc_chains.end(), [&](const auto& q){ return q.first == "bpe"_n; }); + //auto qcc_bpf = std::find_if(ht2._qc_chains.begin(), ht2._qc_chains.end(), [&](const auto& q){ return q.first == "bpf"_n; }); + + std::vector msgs; + + tpm1.set_current_block_id(ids[0]); //first block + tpm2.set_current_block_id(ids[0]); //first block + + tpm1.beat(); //produce first block and associated proposal + tpm2.beat(); //produce first block and associated proposal + + tpm1.dispatch(""); + tpm1.dispatch(""); + + tpm2.dispatch(""); + tpm2.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm1.dispatch(""); + tpm1.dispatch(""); + + tpm2.dispatch(""); + tpm2.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm1.dispatch(""); + tpm1.dispatch(""); + + tpm2.dispatch(""); + tpm2.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm1.dispatch(""); + tpm1.dispatch(""); + + tpm2.dispatch(""); + tpm2.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm1.set_current_block_id(ids[1]); //first block + tpm2.set_current_block_id(alternate_ids[1]); //first block + + tpm1.beat(); //produce second block and associated proposal + tpm2.beat(); //produce second block and associated proposal + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_finality_violation.str(), std::string("5585accc44c753636d1381067c7f915d7fff2d33846aae04820abc055d952860")); + } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_SUITE_END() diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test_pacemaker.cpp index 4b7ba2e9ec..56dfa6c28a 100644 --- a/libraries/hotstuff/test_pacemaker.cpp +++ b/libraries/hotstuff/test_pacemaker.cpp @@ -3,20 +3,6 @@ namespace eosio { namespace hotstuff { -/* void test_pacemaker::init(std::vector unique_replicas){ - - for (name r : unique_replicas){ - - std::set mp{r}; - - register_listener(r, qcc); - - } - - _unique_replicas = unique_replicas; - - };*/ - void test_pacemaker::set_proposer(name proposer){ _proposer = proposer; }; @@ -45,13 +31,33 @@ namespace eosio { namespace hotstuff { _pending_message_queue.push_back(msg); } - std::vector test_pacemaker::flush(){ + void test_pacemaker::pipe(std::vector messages){ + + auto itr = messages.begin(); + + while (itr != messages.end()){ + + _pending_message_queue.push_back(*itr); + + itr++; + } + + } + + std::vector test_pacemaker::dispatch(std::string memo, int count){ + + for (int i = 0 ; i < count ; i++){ + this->dispatch(memo); + } + } + + std::vector test_pacemaker::dispatch(std::string memo){ int count = 1; //ilog(" === propagate ${count} messages", ("count", _pending_message_queue.size())); - std::vector flushed_messages = _pending_message_queue; + std::vector dispatched_messages = _pending_message_queue; _message_queue = _pending_message_queue; while (_pending_message_queue.begin()!=_pending_message_queue.end()){ @@ -65,10 +71,22 @@ namespace eosio { namespace hotstuff { //ilog(" === propagate ${count} messages", ("count", _message_queue.size())); + size_t proposals_count = 0; + size_t votes_count = 0; + size_t new_blocks_count = 0; + size_t new_views_count = 0; + auto msg_itr = _message_queue.begin(); while (msg_itr!=_message_queue.end()){ + size_t v_index = msg_itr->second.index(); + + if(v_index==0) proposals_count++; + if(v_index==1) votes_count++; + if(v_index==2) new_blocks_count++; + if(v_index==3) new_views_count++; + //ilog(" === propagating message ${count} : type : ${index}", ("count", count) ("index", msg_itr->index())); if (msg_itr->second.index() == 0) on_hs_proposal_msg(msg_itr->first, std::get(msg_itr->second)); @@ -98,9 +116,18 @@ namespace eosio { namespace hotstuff { //ilog(" === after erase"); - //ilog(" === end propagate"); + if (memo!=""){ + ilog(" === ${memo} : ", + ("memo", memo)); + } + + ilog(" === pacemaker dispatched ${proposals} proposals, ${votes} votes, ${new_blocks} new_blocks, ${new_views} new_views", + ("proposals", proposals_count) + ("votes", votes_count) + ("new_blocks", new_blocks_count) + ("new_views", new_views_count)); - return _pending_message_queue; + return dispatched_messages; } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 27659d4b3e..dd047f17fa 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1019,7 +1019,7 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->_chain_pacemaker.init(&chain); - my->_qc_chain.init("main"_n, my->_chain_pacemaker, my->_producers, true); + my->_qc_chain.init("main"_n, my->_chain_pacemaker, my->_producers, true, true); } FC_LOG_AND_RETHROW() } From 9c1be07bf8f5c0d00aa9ac1370131cdfaef00418 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Tue, 4 Apr 2023 12:30:57 +0000 Subject: [PATCH 018/151] Misc changes --- .../chain/include/eosio/chain/hotstuff.hpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 6 +- .../include/eosio/hotstuff/base_pacemaker.hpp | 4 +- .../eosio/hotstuff/chain_pacemaker.hpp | 3 +- .../include/eosio/hotstuff/qc_chain.hpp | 9 +- .../include/eosio/hotstuff/test_pacemaker.hpp | 5 +- libraries/hotstuff/qc_chain.cpp | 256 ++++++++++-------- libraries/hotstuff/test/test_hotstuff.cpp | 43 ++- libraries/hotstuff/test_pacemaker.cpp | 15 +- 9 files changed, 198 insertions(+), 145 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 5aa7f43b83..2a2c63de52 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -38,7 +38,7 @@ namespace eosio { namespace chain { bool quorum_met = false; - vector active_finalizers; + fc::unsigned_int active_finalizers; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; }; diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 3fbbdad6e3..be775e7efb 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -73,15 +73,11 @@ namespace eosio { namespace hotstuff { }; - void chain_pacemaker::register_listener(name name, qc_chain& qcc){ + void chain_pacemaker::assign_qc_chain(name name, qc_chain& qcc){ _qc_chain = &qcc; }; - void chain_pacemaker::unregister_listener(name name){ - //delete _qc_chain; - }; - void chain_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ hs_proposal_message_ptr msg_ptr = std::make_shared(msg); diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index c864b6c53f..33941a0f93 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -18,6 +18,7 @@ namespace eosio { namespace hotstuff { //todo : discuss virtual uint32_t get_quorum_threshold() = 0; + virtual block_id_type get_current_block_id() = 0; //hotstuff getters. todo : implement relevant setters as host functions @@ -32,8 +33,7 @@ namespace eosio { namespace hotstuff { //todo : abstract further //qc_chain event subscription - virtual void register_listener(name name, qc_chain& qcc) = 0; - virtual void unregister_listener(name name) = 0; + virtual void assign_qc_chain(name name, qc_chain& qcc) = 0; //outbound communications virtual void send_hs_proposal_msg(name id, hs_proposal_message msg) = 0; diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index 90ee183ab7..2946f8c7d5 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -27,8 +27,7 @@ namespace eosio { namespace hotstuff { uint32_t get_quorum_threshold(); - void register_listener(name name, qc_chain& qcc); - void unregister_listener(name name); + void assign_qc_chain(name name, qc_chain& qcc); void beat(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 0050c7030c..ef4aebe226 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -15,6 +15,9 @@ #include #include +#include + + #include #include @@ -104,12 +107,16 @@ namespace eosio { namespace hotstuff { > proposal_store_type; proposal_store_type _proposal_store; //internal proposals store + + uint32_t positive_bits_count(fc::unsigned_int value); + + fc::unsigned_int update_bitset(fc::unsigned_int value, name finalizer); digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc); //get digest to sign from proposal data void reset_qc(fc::sha256 proposal_id); //reset current internal qc - bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal); //evaluate quorum for a proposal + bool evaluate_quorum(extended_schedule es, fc::unsigned_int finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal); //evaluate quorum for a proposal /* name get_proposer(); name get_leader(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index 12b4afd9a2..e61d0e489a 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -98,9 +98,8 @@ namespace eosio { namespace hotstuff { uint32_t get_quorum_threshold(); - void register_listener(name name, qc_chain& qcc); - void unregister_listener(name name); - + void assign_qc_chain(name name, qc_chain& qcc); + void beat(); void send_hs_proposal_msg(name id, hs_proposal_message msg); diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 3a3aa18f5f..d834d834f2 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -54,6 +54,10 @@ performance testing // test loss of liveness // // test split chain + +// +// store schedules and transition view height, and prune on commit + // // integration with fork_db / LIB overhaul // @@ -61,6 +65,8 @@ performance testing // // regression testing ci/cd -> python regression tests // +// implement bitset for efficiency +// // add APIs for proof data // // add election proposal in block header @@ -71,7 +77,7 @@ performance testing // // keep track of proposals sent to peers // -// allow syncing of proposals +// allow syncing of proposals // // versioning of net protocol version // @@ -79,7 +85,7 @@ performance testing // // system contract update 1 -> allow BPs to register + prove their aggregate pub key. Allow existing BPs to unreg + reg without new aggregate key. Prevent new BPs from registering without proving aggregate pub key // -// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available +// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available // // @@ -87,6 +93,50 @@ performance testing namespace eosio { namespace hotstuff { + uint32_t qc_chain::positive_bits_count(fc::unsigned_int value){ + + boost::dynamic_bitset b(21, value); + + uint32_t count = 0; + + for (boost::dynamic_bitset<>::size_type i = 0; i < b.size(); i++){ + if (b[i]==true)count++; + } + + return count; + + } + + fc::unsigned_int qc_chain::update_bitset(fc::unsigned_int value, name finalizer){ + + /*ilog(" === update bitset ${value} ${finalizer}", + ("value", value) + ("finalizer", finalizer));*/ + + boost::dynamic_bitset b( 21, value ); + + vector finalizers = _pacemaker->get_finalizers(); + + for (size_t i = 0; i < finalizers.size();i++){ + if (finalizers[i] == finalizer){ + + b.flip(i); + + /*ilog(" === finalizer found ${finalizer} new value : ${value}", + ("finalizer", finalizer) + ("value", b.to_ulong()));*/ + + return b.to_ulong(); + } + } + + /*ilog(" *** finalizer not found ${finalizer}", + ("finalizer", finalizer));*/ + + throw std::runtime_error("finalizer not found"); + + } + digest_type qc_chain::get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); @@ -157,7 +207,7 @@ namespace eosio { namespace hotstuff { b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); - if (_log) ilog("=== ${id} creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + if (_log) ilog(" === ${id} creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", ("id", _id) ("block_num", b_new.block_num()) ("phase_counter", b_new.phase_counter) @@ -171,10 +221,10 @@ namespace eosio { namespace hotstuff { void qc_chain::reset_qc(fc::sha256 proposal_id){ - if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); + //if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); _current_qc.proposal_id = proposal_id; _current_qc.quorum_met = false; - _current_qc.active_finalizers = {}; + _current_qc.active_finalizers = 0; _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); } @@ -189,19 +239,28 @@ namespace eosio { namespace hotstuff { return b; } - bool qc_chain::evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ + bool qc_chain::evaluate_quorum(extended_schedule es, fc::unsigned_int finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ + + bool first = true; - if (finalizers.size() < _pacemaker->get_quorum_threshold()){ + if (positive_bits_count(finalizers) < _pacemaker->get_quorum_threshold()){ return false; } - fc::crypto::blslib::bls_public_key agg_key; + boost::dynamic_bitset fb(21, finalizers.value); + + fc::crypto::blslib::bls_public_key agg_key; - for (int i = 0; i < finalizers.size(); i++) { + for (boost::dynamic_bitset<>::size_type i = 0; i < fb.size(); i++) { - //adding finalizer's key to the aggregate pub key - if (i==0) agg_key = _private_key.get_public_key(); - else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); + if (fb[i] == 1){ + //adding finalizer's key to the aggregate pub key + if (first) { + first = false; + agg_key = _private_key.get_public_key(); + } + else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); + } } @@ -226,7 +285,7 @@ namespace eosio { namespace hotstuff { } else { - //ilog("qc : ${qc}", ("qc", qc)); + //ilog(" === qc : ${qc}", ("qc", qc)); bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); @@ -248,30 +307,20 @@ namespace eosio { namespace hotstuff { _my_producers = my_producers; - _pacemaker->register_listener(id, *this); + _pacemaker->assign_qc_chain(id, *this); if (_log) ilog(" === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); - //ilog("bla"); - - //ilog("name ${name}", ("name", *itr)); - - //ilog("111"); + //ilog(" === name ${name}", ("name", *itr)); } bool qc_chain::am_i_proposer(){ - //ilog("am_i_proposer"); - name proposer = _pacemaker->get_proposer(); - //ilog("Proposer : ${proposer}", ("proposer", proposer)); - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); - //ilog("Found"); - if (prod_itr==_my_producers.end()) return false; else return true; @@ -279,23 +328,17 @@ namespace eosio { namespace hotstuff { bool qc_chain::am_i_leader(){ - //ilog("am_i_leader"); - name leader = _pacemaker->get_leader(); - //ilog("Leader : ${leader}", ("leader", leader)); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); - if (prod_itr==_my_producers.end()) return false; - else return true; + if (prod_itr==_my_producers.end()) return false; + else return true; } bool qc_chain::am_i_finalizer(){ - //ilog("am_i_finalizer"); - std::vector finalizers = _pacemaker->get_finalizers(); auto mf_itr = _my_producers.begin(); @@ -330,8 +373,6 @@ namespace eosio { namespace hotstuff { return v_msg; - //ilog("signed proposal. Broadcasting for each of my producers"); - } void qc_chain::process_proposal(hs_proposal_message proposal){ @@ -343,7 +384,7 @@ namespace eosio { namespace hotstuff { auto jp_itr = _proposal_store.get().find( proposal.justify.proposal_id ); if (jp_itr == _proposal_store.get().end()) { - if (_errors) ilog("*** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); + if (_errors) ilog(" *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); return; //can't recognize a proposal with an unknown justification } @@ -419,11 +460,11 @@ namespace eosio { namespace hotstuff { hs_vote_message v_msg = sign_proposal(proposal, *prod_itr); - if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", +/* if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id)); + ("proposal_id", proposal.proposal_id));*/ send_hs_vote_msg(v_msg); @@ -434,11 +475,11 @@ namespace eosio { namespace hotstuff { } } - else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", +/* else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id)); + ("proposal_id", proposal.proposal_id));*/ //update internal state @@ -446,8 +487,6 @@ namespace eosio { namespace hotstuff { //check for leader change leader_rotation_check(); - - //ilog("process_proposal end"); auto total_time = fc::time_point::now() - start; @@ -465,7 +504,7 @@ namespace eosio { namespace hotstuff { if(!am_leader) return; - //ilog("=== Process vote from ${finalizer}", ("finalizer", vote.finalizer)); + //ilog(" === Process vote from ${finalizer} : current bitset ${value}" , ("finalizer", vote.finalizer)("value", _current_qc.active_finalizers)); //only leader need to take action on votes @@ -474,35 +513,36 @@ namespace eosio { namespace hotstuff { proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); if (p_itr==_proposal_store.get().end()){ - if (_errors) ilog("*** ${id} couldn't find proposal", ("id",_id)); + if (_errors) ilog(" *** ${id} couldn't find proposal", ("id",_id)); - if (_errors) ilog("*** ${id} vote : ${vote}", ("vote", vote)("id",_id)); + if (_errors) ilog(" *** ${id} vote : ${vote}", ("vote", vote)("id",_id)); return; } bool quorum_met = _current_qc.quorum_met; //check if quorum already met + //if quorum is already met, we don't need to do anything else. Otherwise, we aggregate the signature if (!quorum_met){ - _current_qc.active_finalizers.push_back(vote.finalizer); - - if (_current_qc.active_finalizers.size()>1) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); + if (_current_qc.active_finalizers>0) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); else _current_qc.active_agg_sig = vote.sig; + _current_qc.active_finalizers = update_bitset(_current_qc.active_finalizers, vote.finalizer); + quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); if (quorum_met){ _current_qc.quorum_met = true; - if (_log) ilog("=== ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", + if (_log) ilog(" === ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", ("block_num", p_itr->block_num()) ("phase_counter", p_itr->phase_counter) ("proposal_id", vote.proposal_id) ("id", _id)); - //ilog("=== update_high_qc : _current_qc ==="); + //ilog(" === update_high_qc : _current_qc ==="); update_high_qc(_current_qc); //check for leader change @@ -511,7 +551,7 @@ namespace eosio { namespace hotstuff { //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet if (_chained_mode==false && p_itr->phase_counter<3){ - if (_log) ilog(" === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); + //if (_log) ilog(" === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); hs_proposal_message proposal_candidate; @@ -520,14 +560,14 @@ namespace eosio { namespace hotstuff { reset_qc(proposal_candidate.proposal_id); - if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); + //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); _pending_proposal_block = NULL_BLOCK_ID; send_hs_proposal_msg(proposal_candidate); _b_leaf = proposal_candidate.proposal_id; - if (_log) ilog(" === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); + //if (_log) ilog(" === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); } @@ -543,20 +583,20 @@ namespace eosio { namespace hotstuff { void qc_chain::process_new_view(hs_new_view_message new_view){ - if (_log) ilog("=== ${id} process_new_view === ${qc}", ("qc", new_view.high_qc)("id", _id)); + //if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", new_view.high_qc)("id", _id)); update_high_qc(new_view.high_qc); } void qc_chain::process_new_block(hs_new_block_message msg){ - //ilog("=== Process new block ==="); + //ilog(" === Process new block ==="); } void qc_chain::send_hs_proposal_msg(hs_proposal_message msg){ - //ilog("=== broadcast_hs_proposal ==="); + //ilog(" === broadcast_hs_proposal ==="); //hs_proposal_message_ptr ptr = std::make_shared(msg); @@ -569,7 +609,7 @@ namespace eosio { namespace hotstuff { void qc_chain::send_hs_vote_msg(hs_vote_message msg){ - //ilog("=== broadcast_hs_vote ==="); + //ilog(" === broadcast_hs_vote ==="); //hs_vote_message_ptr ptr = std::make_shared(msg); @@ -581,7 +621,7 @@ namespace eosio { namespace hotstuff { void qc_chain::send_hs_new_view_msg(hs_new_view_message msg){ - //ilog("=== broadcast_hs_new_view ==="); + //ilog(" === broadcast_hs_new_view ==="); //hs_new_view_message_ptr ptr = std::make_shared(msg); @@ -591,7 +631,7 @@ namespace eosio { namespace hotstuff { void qc_chain::send_hs_new_block_msg(hs_new_block_message msg){ - //ilog("=== broadcast_hs_new_block ==="); + //ilog(" === broadcast_hs_new_block ==="); //hs_new_block_message_ptr ptr = std::make_shared(msg); @@ -614,7 +654,7 @@ namespace eosio { namespace hotstuff { if (itr->proposal_id == ancestor){ if (counter>25) { - if (_errors) ilog("*** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); + if (_errors) ilog(" *** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); } return true; @@ -639,7 +679,7 @@ try{ auto start = fc::time_point::now(); - if (_log) ilog(" === ${id} on beat === ", ("id", _id)); + //if (_log) ilog(" === ${id} on beat === ", ("id", _id)); //std::lock_guard g( this-> _hotstuff_state_mutex ); @@ -647,24 +687,16 @@ try{ if (current_producer == "eosio"_n) return; - //ilog("current_producer : ${current_producer}", ("current_producer", current_producer)); - block_id_type current_block_id = _pacemaker->get_current_block_id(); - //ilog("current_block_id : ${current_block_id}", ("current_block_id", current_block_id)); - //ilog(" === qc chain on_beat ${my_producers}", ("my_producers", _my_producers)); - //ilog("222"); - bool am_proposer = am_i_proposer(); - //ilog("am i proposer received"); - bool am_leader = am_i_leader(); - if (_log) ilog(" === ${id} am_proposer = ${am_proposer}", ("am_proposer", am_proposer)("id", _id)); - if (_log) ilog(" === ${id} am_leader = ${am_leader}", ("am_leader", am_leader)("id", _id)); + //if (_log) ilog(" === ${id} am_proposer = ${am_proposer}", ("am_proposer", am_proposer)("id", _id)); + //if (_log) ilog(" === ${id} am_leader = ${am_leader}", ("am_leader", am_leader)("id", _id)); if (!am_proposer && !am_leader){ @@ -684,35 +716,36 @@ try{ if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ - +/* if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", ("id", _id) ("proposal_id", _current_qc.proposal_id) ("quorum_met", _current_qc.quorum_met)); - if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", current_block_id)); + if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", current_block_id));*/ _pending_proposal_block = current_block_id; } else { - if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", +/* if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", ("id", _id) ("proposal_id", _current_qc.proposal_id) ("quorum_met", _current_qc.quorum_met)); - +*/ hs_proposal_message proposal_candidate = new_proposal_candidate(current_block_id, 0 ); reset_qc(proposal_candidate.proposal_id); - if (_log) ilog(" === ${id} setting _pending_proposal_block to null (on_beat)", ("id", _id)); + //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (on_beat)", ("id", _id)); + _pending_proposal_block = NULL_BLOCK_ID; send_hs_proposal_msg(proposal_candidate); _b_leaf = proposal_candidate.proposal_id; - if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); + //if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); } @@ -723,7 +756,7 @@ try{ hs_new_block_message block_candidate = new_block_candidate(current_block_id); - //ilog("=== broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); + //ilog(" === broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); send_hs_new_block_msg(block_candidate); @@ -744,7 +777,7 @@ handle_eptr(eptr); void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ - //ilog("=== check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); + //ilog(" === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); // if new high QC is higher than current, update to new @@ -754,7 +787,7 @@ handle_eptr(eptr); _high_qc = high_qc; _b_leaf = _high_qc.proposal_id; - if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); + //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } else { @@ -777,12 +810,12 @@ handle_eptr(eptr); high_qc.quorum_met = true; - //ilog("=== updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); + //ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); _high_qc = high_qc; _b_leaf = _high_qc.proposal_id; - if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); + //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } @@ -794,8 +827,6 @@ handle_eptr(eptr); void qc_chain::leader_rotation_check(){ - //ilog("leader_rotation_check"); - //verify if leader changed name current_leader = _pacemaker->get_leader() ; @@ -812,7 +843,8 @@ handle_eptr(eptr); reset_qc(NULL_PROPOSAL_ID); - if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); + //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); + _pending_proposal_block = NULL_BLOCK_ID; hs_new_view_message new_view; @@ -828,7 +860,7 @@ handle_eptr(eptr); //safenode predicate bool qc_chain::is_node_safe(hs_proposal_message proposal){ - //ilog("=== is_node_safe ==="); + //ilog(" === is_node_safe ==="); bool monotony_check = false; bool safety_check = false; @@ -898,14 +930,14 @@ handle_eptr(eptr); } else { - if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); + //if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); //if we're not locked on anything, means the protocol just activated or chain just launched liveness_check = true; safety_check = true; } -/* ilog("=== final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", +/* ilog(" === final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", ("final_on_qc_check", final_on_qc_check) ("monotony_check", monotony_check) ("liveness_check", liveness_check) @@ -932,7 +964,7 @@ handle_eptr(eptr); std::exception_ptr eptr; try{ - //ilog("=== ${id} qc on_hs_proposal_msg ===", ("id", _id)); + //ilog(" === ${id} qc on_hs_proposal_msg ===", ("id", _id)); //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block @@ -952,7 +984,7 @@ handle_eptr(eptr); std::exception_ptr eptr; try{ - //ilog("=== ${id} qc on_hs_vote_msg ===", ("id", _id)); + //ilog(" === ${id} qc on_hs_vote_msg ===", ("id", _id)); //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block @@ -972,7 +1004,7 @@ handle_eptr(eptr); std::exception_ptr eptr; try{ - //ilog("=== ${id} qc on_hs_new_view_msg ===", ("id", _id)); + //ilog(" === ${id} qc on_hs_new_view_msg ===", ("id", _id)); //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block @@ -992,7 +1024,7 @@ handle_eptr(eptr); std::exception_ptr eptr; try{ - //ilog("=== ${id} qc on_hs_new_block_msg ===", ("id", _id)); + //ilog(" === ${id} qc on_hs_new_block_msg ===", ("id", _id)); //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block @@ -1009,7 +1041,7 @@ handle_eptr(eptr); void qc_chain::update(hs_proposal_message proposal){ - //ilog("=== update internal state ==="); + //ilog(" === update internal state ==="); //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ @@ -1023,7 +1055,7 @@ handle_eptr(eptr); proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock); - //ilog("=== update_high_qc : proposal.justify ==="); + //ilog(" === update_high_qc : proposal.justify ==="); update_high_qc(proposal.justify); if (chain_length<1){ @@ -1045,20 +1077,20 @@ handle_eptr(eptr); //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock - if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height} b_lock height ${b_lock_height}", +/* if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height} b_lock height ${b_lock_height}", ("id", _id) ("_b_lock", _b_lock) ("b_1_height", b_1.block_num()) ("b_1_phase", b_1.phase_counter) ("b_lock_height", b_lock->block_num()) - ("b_lock_phase", b_lock->phase_counter)); + ("b_lock_phase", b_lock->phase_counter));*/ if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); _b_lock = b_1.proposal_id; //commit phase on b1 - if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); + //if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); } @@ -1071,7 +1103,7 @@ handle_eptr(eptr); hs_proposal_message b = *itr; -/* ilog("direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", +/* ilog(" === direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", ("b_2.parent_id",b_2.parent_id) ("b_1.proposal_id", b_1.proposal_id) ("b_1.parent_id", b_1.parent_id) @@ -1080,8 +1112,6 @@ handle_eptr(eptr); //direct parent relationship verification if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ - //ilog("direct parent relationship verified"); - if (_b_exec!= NULL_PROPOSAL_ID){ proposal_store_type::nth_index<0>::type::iterator b_exec = _proposal_store.get().find( _b_exec); @@ -1107,24 +1137,21 @@ handle_eptr(eptr); commit(b); - //ilog("last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); + //ilog(" === last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); - //ilog("setting _b_exec to ${proposal_id}", ("proposal_id",b.proposal_id )); _b_exec = b.proposal_id; //decide phase on b _block_exec = b.block_id; gc_proposals( b.get_height()-1); - //ilog("completed commit"); - } else { if (_errors) ilog(" *** ${id} could not verify direct parent relationship", ("id",_id)); - if (_errors) ilog(" *** b_2 ${b_2}", ("b_2", b_2)); - if (_errors) ilog(" *** b_1 ${b_1}", ("b_1", b_1)); - if (_errors) ilog(" *** b ${b}", ("b", b)); + if (_errors) ilog(" *** b_2 ${b_2}", ("b_2", b_2)); + if (_errors) ilog(" *** b_1 ${b_1}", ("b_1", b_1)); + if (_errors) ilog(" *** b ${b}", ("b", b)); } @@ -1133,7 +1160,7 @@ handle_eptr(eptr); void qc_chain::gc_proposals(uint64_t cutoff){ - //ilog("garbage collection on old data"); + //ilog(" === garbage collection on old data"); auto end_itr = _proposal_store.get().upper_bound(cutoff); @@ -1141,12 +1168,12 @@ handle_eptr(eptr); auto itr = _proposal_store.get().begin(); - if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", +/* if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", ("id", _id) ("block_num", itr->block_num()) ("phase_counter", itr->phase_counter) ("block_id", itr->block_id) - ("proposal_id", itr->proposal_id)); + ("proposal_id", itr->proposal_id));*/ _proposal_store.get().erase(itr); @@ -1157,7 +1184,7 @@ handle_eptr(eptr); void qc_chain::commit(hs_proposal_message proposal){ -/* ilog("=== attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", +/* ilog(" === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", ("block_num", proposal.block_num()) ("proposal_id", proposal.proposal_id) ("block_id", proposal.block_id) @@ -1168,7 +1195,7 @@ handle_eptr(eptr); proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); -/* ilog("=== _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", +/* ilog(" === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", ("block_num", last_exec_prop->block_num()) ("proposal_id", last_exec_prop->proposal_id) ("block_id", last_exec_prop->block_id) @@ -1182,7 +1209,6 @@ handle_eptr(eptr); ("phase_counter_2", proposal.phase_counter));*/ if (_b_exec==NULL_PROPOSAL_ID){ - //ilog("first block committed"); exec_height_check = true; } else exec_height_check = last_exec_prop->get_height() < proposal.get_height(); @@ -1193,7 +1219,7 @@ handle_eptr(eptr); if (p_itr != _proposal_store.get().end()){ - //ilog("=== recursively committing" ); + //ilog(" === recursively committing" ); commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 4400861372..98262a6168 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -5,6 +5,10 @@ #include +#include + +#include + #include #include @@ -162,6 +166,37 @@ class hotstuff_test_handler { BOOST_AUTO_TEST_SUITE(hotstuff) +BOOST_AUTO_TEST_CASE(hotstuff_bitset) try { + + boost::dynamic_bitset b( 8, 0 ); + + uint32_t c = b.to_ulong(); + + b.flip(0); //least significant bit + b.flip(1); + b.flip(2); + b.flip(3); + b.flip(4); + b.flip(5); + b.flip(6); + b.flip(7); //most significant bit + + uint32_t d = b.to_ulong(); + + for (boost::dynamic_bitset<>::size_type i = 0; i < b.size(); ++i){ + b.flip(i); + } + + uint32_t e = b.to_ulong(); + + std::cout << "c : " << c << "\n"; + std::cout << "d : " << d << "\n"; + std::cout << "e : " << e << "\n"; + + +} FC_LOG_AND_RETHROW(); + + BOOST_AUTO_TEST_CASE(hotstuff_1) try { //test optimistic responsiveness (3 confirmations per block) @@ -170,7 +205,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n}, {"bpa"_n}, unique_replicas); + ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n}, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); @@ -180,12 +215,16 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); +ht.print_bp_state("bpa"_n, ""); + tpm.set_current_block_id(ids[0]); //first block tpm.beat(); //produce first block and associated proposal tpm.dispatch(""); //send proposal to replicas (prepare on first block) +ht.print_bp_state("bpa"_n, ""); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -271,7 +310,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - + } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_CASE(hotstuff_2) try { diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test_pacemaker.cpp index 56dfa6c28a..075c888920 100644 --- a/libraries/hotstuff/test_pacemaker.cpp +++ b/libraries/hotstuff/test_pacemaker.cpp @@ -188,7 +188,7 @@ namespace eosio { namespace hotstuff { }; - void test_pacemaker::register_listener(name name, qc_chain& qcc){ + void test_pacemaker::assign_qc_chain(name name, qc_chain& qcc){ //ilog("reg listener"); @@ -225,19 +225,6 @@ namespace eosio { namespace hotstuff { } - }; - - void test_pacemaker::unregister_listener(name name){ - - auto itr = _qcc_store.get().find( name.to_uint64_t() ); - - if (itr!= _qcc_store.end()) { - - _qcc_store.erase(itr); - - } - else throw std::runtime_error("qc chain not found"); - }; void test_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ From bdfd95e2575f77ef61480bc6242e027d90b42b2c Mon Sep 17 00:00:00 2001 From: fcecin Date: Tue, 11 Apr 2023 22:10:27 -0300 Subject: [PATCH 019/151] light formatting --- .../chain/include/eosio/chain/hotstuff.hpp | 196 +- libraries/hotstuff/chain_pacemaker.cpp | 237 +- .../include/eosio/hotstuff/base_pacemaker.hpp | 102 +- .../eosio/hotstuff/chain_pacemaker.hpp | 107 +- .../include/eosio/hotstuff/qc_chain.hpp | 377 ++- .../include/eosio/hotstuff/test_pacemaker.hpp | 256 +- libraries/hotstuff/qc_chain.cpp | 2265 ++++++++--------- libraries/hotstuff/test/test_hotstuff.cpp | 1674 ++++++------ libraries/hotstuff/test_pacemaker.cpp | 618 ++--- 9 files changed, 2708 insertions(+), 3124 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 2a2c63de52..be091882e4 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -1,111 +1,85 @@ -#pragma once -#include -#include -#include -#include -#include -#include -#include - -namespace eosio { namespace chain { - - - const block_id_type NULL_BLOCK_ID = block_id_type("00"); - const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - - static uint32_t compute_block_num(block_id_type block_id) - { - return fc::endian_reverse_u32(block_id._hash[0]); - } - - static uint64_t compute_height(uint32_t block_height, uint32_t phase_counter){ - return (uint64_t{block_height} << 32) | phase_counter; - } - - struct extended_schedule { - - producer_authority_schedule producer_schedule; - - std::map bls_pub_keys; - - }; - - struct quorum_certificate { - - public: - - fc::sha256 proposal_id = NULL_PROPOSAL_ID; - - bool quorum_met = false; - - fc::unsigned_int active_finalizers; //bitset encoding, following canonical order - fc::crypto::blslib::bls_signature active_agg_sig; - - }; - - struct hs_vote_message { - - fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal - - name finalizer; - fc::crypto::blslib::bls_signature sig; - - hs_vote_message() = default; - - }; - - struct hs_proposal_message { - - fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal - - block_id_type block_id = NULL_BLOCK_ID; - uint8_t phase_counter = 0; - - fc::sha256 parent_id = NULL_PROPOSAL_ID; //new proposal - - fc::sha256 final_on_qc = NULL_PROPOSAL_ID; - - quorum_certificate justify; //justification - - hs_proposal_message() = default; - - uint32_t block_num()const{ - return compute_block_num(block_id); - } - - uint64_t get_height()const { - return compute_height(compute_block_num(block_id), phase_counter); - }; - - }; - - struct hs_new_block_message { - - block_id_type block_id = NULL_BLOCK_ID; //new proposal - - quorum_certificate justify; //justification - - hs_new_block_message() = default; - }; - - struct hs_new_view_message { - - quorum_certificate high_qc; //justification - - hs_new_view_message() = default; - - }; - - using hs_proposal_message_ptr = std::shared_ptr; - using hs_vote_message_ptr = std::shared_ptr; - - using hs_new_view_message_ptr = std::shared_ptr; - using hs_new_block_message_ptr = std::shared_ptr; - -}} //eosio::chain - -FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); -FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); -FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(phase_counter)(parent_id)(final_on_qc)(justify)); -FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify)); -FC_REFLECT(eosio::chain::hs_new_view_message, (high_qc)); \ No newline at end of file +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace eosio { namespace chain { + + const block_id_type NULL_BLOCK_ID = block_id_type("00"); + const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); + + static uint32_t compute_block_num(block_id_type block_id){ + return fc::endian_reverse_u32(block_id._hash[0]); + } + + static uint64_t compute_height(uint32_t block_height, uint32_t phase_counter){ + return (uint64_t{block_height} << 32) | phase_counter; + } + + struct extended_schedule { + producer_authority_schedule producer_schedule; + std::map bls_pub_keys; + }; + + struct quorum_certificate { + fc::sha256 proposal_id = NULL_PROPOSAL_ID; + bool quorum_met = false; + fc::unsigned_int active_finalizers; //bitset encoding, following canonical order + fc::crypto::blslib::bls_signature active_agg_sig; + }; + + struct hs_vote_message { + fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal + name finalizer; + fc::crypto::blslib::bls_signature sig; + + hs_vote_message() = default; + }; + + struct hs_proposal_message { + fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal + block_id_type block_id = NULL_BLOCK_ID; + uint8_t phase_counter = 0; + fc::sha256 parent_id = NULL_PROPOSAL_ID; //new proposal + fc::sha256 final_on_qc = NULL_PROPOSAL_ID; + quorum_certificate justify; //justification + + hs_proposal_message() = default; + + uint32_t block_num()const { + return compute_block_num(block_id); + } + + uint64_t get_height()const { + return compute_height(compute_block_num(block_id), phase_counter); + }; + }; + + struct hs_new_block_message { + block_id_type block_id = NULL_BLOCK_ID; //new proposal + quorum_certificate justify; //justification + hs_new_block_message() = default; + }; + + struct hs_new_view_message { + quorum_certificate high_qc; //justification + hs_new_view_message() = default; + }; + + using hs_proposal_message_ptr = std::shared_ptr; + using hs_vote_message_ptr = std::shared_ptr; + + using hs_new_view_message_ptr = std::shared_ptr; + using hs_new_block_message_ptr = std::shared_ptr; + +}} //eosio::chain + +FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); +FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); +FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(phase_counter)(parent_id)(final_on_qc)(justify)); +FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify)); +FC_REFLECT(eosio::chain::hs_new_view_message, (high_qc)); diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index be775e7efb..a1646d8a64 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -1,141 +1,96 @@ -#include -#include - -namespace eosio { namespace hotstuff { - - - void chain_pacemaker::init(controller* chain){ - _chain = chain; - } - - name chain_pacemaker::get_proposer(){ - - const block_state_ptr& hbs = _chain->head_block_state(); - - return hbs->header.producer; - - }; - - name chain_pacemaker::get_leader(){ - - const block_state_ptr& hbs = _chain->head_block_state(); - - return hbs->header.producer; - - }; - - name chain_pacemaker::get_next_leader(){ - - const block_state_ptr& hbs = _chain->head_block_state(); - - block_timestamp_type next_block_time = hbs->header.timestamp.next(); - - producer_authority p_auth = hbs->get_scheduled_producer(next_block_time); - - return p_auth.producer_name; - - }; - - std::vector chain_pacemaker::get_finalizers(){ - - const block_state_ptr& hbs = _chain->head_block_state(); - - std::vector pa_list = hbs->active_schedule.producers; - - std::vector pn_list; - std::transform(pa_list.begin(), pa_list.end(), - std::back_inserter(pn_list), - [](const producer_authority& p) { return p.producer_name; }); - - return pn_list; - - }; - - block_id_type chain_pacemaker::get_current_block_id(){ - - block_header header = _chain->head_block_state()->header; - - block_id_type block_id = header.calculate_id(); - - return block_id; - - } - - uint32_t chain_pacemaker::get_quorum_threshold(){ - return _quorum_threshold; - }; - - void chain_pacemaker::beat(){ - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - _qc_chain->on_beat(); - - }; - - void chain_pacemaker::assign_qc_chain(name name, qc_chain& qcc){ - _qc_chain = &qcc; - - }; - - void chain_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ - - hs_proposal_message_ptr msg_ptr = std::make_shared(msg); - - _chain->commit_hs_proposal_msg(msg_ptr); - - }; - - void chain_pacemaker::send_hs_vote_msg(name id, hs_vote_message msg){ - - hs_vote_message_ptr msg_ptr = std::make_shared(msg); - - _chain->commit_hs_vote_msg(msg_ptr); - - }; - - void chain_pacemaker::send_hs_new_block_msg(name id, hs_new_block_message msg){ - - hs_new_block_message_ptr msg_ptr = std::make_shared(msg); - - _chain->commit_hs_new_block_msg(msg_ptr); - - }; - - void chain_pacemaker::send_hs_new_view_msg(name id, hs_new_view_message msg){ - - hs_new_view_message_ptr msg_ptr = std::make_shared(msg); - - _chain->commit_hs_new_view_msg(msg_ptr); - - }; - - void chain_pacemaker::on_hs_proposal_msg(name id, hs_proposal_message msg){ - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - _qc_chain->on_hs_proposal_msg(msg); - } - - void chain_pacemaker::on_hs_vote_msg(name id, hs_vote_message msg){ - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - _qc_chain->on_hs_vote_msg(msg); - } - - void chain_pacemaker::on_hs_new_block_msg(name id, hs_new_block_message msg){ - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - _qc_chain->on_hs_new_block_msg(msg); - } - - void chain_pacemaker::on_hs_new_view_msg(name id, hs_new_view_message msg){ - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - _qc_chain->on_hs_new_view_msg(msg); - } - -}} \ No newline at end of file +#include +#include + +namespace eosio { namespace hotstuff { + + void chain_pacemaker::init(controller* chain){ + _chain = chain; + } + + name chain_pacemaker::get_proposer(){ + const block_state_ptr& hbs = _chain->head_block_state(); + return hbs->header.producer; + } + + name chain_pacemaker::get_leader(){ + const block_state_ptr& hbs = _chain->head_block_state(); + return hbs->header.producer; + } + + name chain_pacemaker::get_next_leader(){ + const block_state_ptr& hbs = _chain->head_block_state(); + block_timestamp_type next_block_time = hbs->header.timestamp.next(); + producer_authority p_auth = hbs->get_scheduled_producer(next_block_time); + return p_auth.producer_name; + } + + std::vector chain_pacemaker::get_finalizers(){ + const block_state_ptr& hbs = _chain->head_block_state(); + std::vector pa_list = hbs->active_schedule.producers; + std::vector pn_list; + std::transform(pa_list.begin(), pa_list.end(), + std::back_inserter(pn_list), + [](const producer_authority& p) { return p.producer_name; }); + return pn_list; + } + + block_id_type chain_pacemaker::get_current_block_id(){ + block_header header = _chain->head_block_state()->header; + block_id_type block_id = header.calculate_id(); + return block_id; + } + + uint32_t chain_pacemaker::get_quorum_threshold(){ + return _quorum_threshold; + } + + void chain_pacemaker::beat(){ + std::lock_guard g( this-> _hotstuff_state_mutex ); + _qc_chain->on_beat(); + } + + void chain_pacemaker::assign_qc_chain(name name, qc_chain& qcc){ + _qc_chain = &qcc; + } + + void chain_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ + hs_proposal_message_ptr msg_ptr = std::make_shared(msg); + _chain->commit_hs_proposal_msg(msg_ptr); + } + + void chain_pacemaker::send_hs_vote_msg(name id, hs_vote_message msg){ + hs_vote_message_ptr msg_ptr = std::make_shared(msg); + _chain->commit_hs_vote_msg(msg_ptr); + } + + void chain_pacemaker::send_hs_new_block_msg(name id, hs_new_block_message msg){ + hs_new_block_message_ptr msg_ptr = std::make_shared(msg); + _chain->commit_hs_new_block_msg(msg_ptr); + } + + void chain_pacemaker::send_hs_new_view_msg(name id, hs_new_view_message msg){ + hs_new_view_message_ptr msg_ptr = std::make_shared(msg); + _chain->commit_hs_new_view_msg(msg_ptr); + } + + void chain_pacemaker::on_hs_proposal_msg(name id, hs_proposal_message msg){ + std::lock_guard g( this-> _hotstuff_state_mutex ); + _qc_chain->on_hs_proposal_msg(msg); + } + + void chain_pacemaker::on_hs_vote_msg(name id, hs_vote_message msg){ + std::lock_guard g( this-> _hotstuff_state_mutex ); + _qc_chain->on_hs_vote_msg(msg); + } + + void chain_pacemaker::on_hs_new_block_msg(name id, hs_new_block_message msg){ + std::lock_guard g( this-> _hotstuff_state_mutex ); + _qc_chain->on_hs_new_block_msg(msg); + } + + void chain_pacemaker::on_hs_new_view_msg(name id, hs_new_view_message msg){ + std::lock_guard g( this-> _hotstuff_state_mutex ); + _qc_chain->on_hs_new_view_msg(msg); + } + +}} diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index 33941a0f93..301ce14869 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -1,52 +1,50 @@ -#pragma once - -#include -//#include -#include -#include -#include - -using namespace eosio::chain; - -namespace eosio { namespace hotstuff { - - class qc_chain; - - class base_pacemaker{ - - public: - - //todo : discuss - virtual uint32_t get_quorum_threshold() = 0; - - virtual block_id_type get_current_block_id() = 0; - - //hotstuff getters. todo : implement relevant setters as host functions - virtual name get_proposer() = 0; - virtual name get_leader() = 0; - virtual name get_next_leader() = 0; - virtual std::vector get_finalizers() = 0; - - //block / proposal API - virtual void beat() = 0; - - //todo : abstract further - - //qc_chain event subscription - virtual void assign_qc_chain(name name, qc_chain& qcc) = 0; - - //outbound communications - virtual void send_hs_proposal_msg(name id, hs_proposal_message msg) = 0; - virtual void send_hs_vote_msg(name id, hs_vote_message msg) = 0; - virtual void send_hs_new_block_msg(name id, hs_new_block_message msg) = 0; - virtual void send_hs_new_view_msg(name id, hs_new_view_message msg) = 0; - - //inbound communications - virtual void on_hs_vote_msg(name id, hs_vote_message msg) = 0; //confirmation msg event handler - virtual void on_hs_proposal_msg(name id, hs_proposal_message msg) = 0; //consensus msg event handler - virtual void on_hs_new_view_msg(name id, hs_new_view_message msg) = 0; //new view msg event handler - virtual void on_hs_new_block_msg(name id, hs_new_block_message msg) = 0; //new block msg event handler - - }; - -}} \ No newline at end of file +#pragma once + +#include +//#include +#include +#include +#include + +using namespace eosio::chain; + +namespace eosio { namespace hotstuff { + + class qc_chain; + + class base_pacemaker { + public: + + //todo : discuss + virtual uint32_t get_quorum_threshold() = 0; + + virtual block_id_type get_current_block_id() = 0; + + //hotstuff getters. todo : implement relevant setters as host functions + virtual name get_proposer() = 0; + virtual name get_leader() = 0; + virtual name get_next_leader() = 0; + virtual std::vector get_finalizers() = 0; + + //block / proposal API + virtual void beat() = 0; + + //todo : abstract further + + //qc_chain event subscription + virtual void assign_qc_chain(name name, qc_chain& qcc) = 0; + + //outbound communications + virtual void send_hs_proposal_msg(name id, hs_proposal_message msg) = 0; + virtual void send_hs_vote_msg(name id, hs_vote_message msg) = 0; + virtual void send_hs_new_block_msg(name id, hs_new_block_message msg) = 0; + virtual void send_hs_new_view_msg(name id, hs_new_view_message msg) = 0; + + //inbound communications + virtual void on_hs_vote_msg(name id, hs_vote_message msg) = 0; //confirmation msg event handler + virtual void on_hs_proposal_msg(name id, hs_proposal_message msg) = 0; //consensus msg event handler + virtual void on_hs_new_view_msg(name id, hs_new_view_message msg) = 0; //new view msg event handler + virtual void on_hs_new_block_msg(name id, hs_new_block_message msg) = 0; //new block msg event handler + }; + +}} diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index 2946f8c7d5..c25240e600 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -1,55 +1,52 @@ -#pragma once -#include -#include - -#include - -namespace eosio { namespace hotstuff { - - class chain_pacemaker : public base_pacemaker { - - public: - - //class-specific functions - - void init(controller* chain); - - std::mutex _hotstuff_state_mutex; - - //base_pacemaker interface functions - - name get_proposer(); - name get_leader() ; - name get_next_leader() ; - std::vector get_finalizers(); - - block_id_type get_current_block_id(); - - uint32_t get_quorum_threshold(); - - void assign_qc_chain(name name, qc_chain& qcc); - - void beat(); - - void send_hs_proposal_msg(name id, hs_proposal_message msg); - void send_hs_vote_msg(name id, hs_vote_message msg); - void send_hs_new_block_msg(name id, hs_new_block_message msg); - void send_hs_new_view_msg(name id, hs_new_view_message msg); - - void on_hs_vote_msg(name id, hs_vote_message msg); //confirmation msg event handler - void on_hs_proposal_msg(name id, hs_proposal_message msg); //consensus msg event handler - void on_hs_new_view_msg(name id, hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(name id, hs_new_block_message msg); //new block msg event handler - - - private : - - chain::controller* _chain = NULL; - - qc_chain* _qc_chain = NULL; - - uint32_t _quorum_threshold = 15; //todo : calculate from schedule - - }; - -}} \ No newline at end of file +#pragma once +#include +#include + +#include + +namespace eosio { namespace hotstuff { + + class chain_pacemaker : public base_pacemaker { + public: + + //class-specific functions + + void init(controller* chain); + + std::mutex _hotstuff_state_mutex; + + //base_pacemaker interface functions + + name get_proposer(); + name get_leader() ; + name get_next_leader() ; + std::vector get_finalizers(); + + block_id_type get_current_block_id(); + + uint32_t get_quorum_threshold(); + + void assign_qc_chain(name name, qc_chain& qcc); + + void beat(); + + void send_hs_proposal_msg(name id, hs_proposal_message msg); + void send_hs_vote_msg(name id, hs_vote_message msg); + void send_hs_new_block_msg(name id, hs_new_block_message msg); + void send_hs_new_view_msg(name id, hs_new_view_message msg); + + void on_hs_vote_msg(name id, hs_vote_message msg); //confirmation msg event handler + void on_hs_proposal_msg(name id, hs_proposal_message msg); //consensus msg event handler + void on_hs_new_view_msg(name id, hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(name id, hs_new_block_message msg); //new block msg event handler + + private: + + chain::controller* _chain = nullptr; + + qc_chain* _qc_chain = nullptr; + + uint32_t _quorum_threshold = 15; //todo : calculate from schedule + }; + +}} diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index ef4aebe226..1542d62e43 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -1,193 +1,184 @@ -#pragma once -#include -//#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - - - -#include -#include - -#include - -namespace eosio { namespace hotstuff { - - using boost::multi_index_container; - using namespace boost::multi_index; - - using namespace eosio::chain; - - //const uint32_t INTERUPT_TIMEOUT = 6; //sufficient timeout for new leader to be selected - - class qc_chain { - public: - - static void handle_eptr(std::exception_ptr eptr){ - try { - if (eptr) { - std::rethrow_exception(eptr); - } - } catch(const std::exception& e) { - ilog("Caught exception ${ex}" , ("ex", e.what())); - std::exit(0); - } - }; - - - //todo : remove. bls12-381 key used for testing purposes - std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, - 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, - 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; - - fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); - - enum msg_type { - new_view = 1, - new_block = 2, - qc = 3, - vote = 4 - }; - - - bool _chained_mode = false ; - - fc::sha256 _b_leaf = NULL_PROPOSAL_ID; - fc::sha256 _b_lock = NULL_PROPOSAL_ID; - fc::sha256 _b_exec = NULL_PROPOSAL_ID; - - fc::sha256 _b_finality_violation = NULL_PROPOSAL_ID; - - block_id_type _block_exec = NULL_BLOCK_ID; - - block_id_type _pending_proposal_block = NULL_BLOCK_ID; - - uint32_t _v_height; - - bool _log = true; - bool _errors = true; - - eosio::chain::quorum_certificate _high_qc; - eosio::chain::quorum_certificate _current_qc; - - eosio::chain::extended_schedule _schedule; - - std::set _my_producers; - - name _id; - - struct by_proposal_id{}; - struct by_proposal_height{}; - - typedef multi_index_container< - hs_proposal_message, - indexed_by< - hashed_unique< - tag, - BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) - >, - ordered_non_unique< - tag, - BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) - > - > - > proposal_store_type; - - proposal_store_type _proposal_store; //internal proposals store - - uint32_t positive_bits_count(fc::unsigned_int value); - - fc::unsigned_int update_bitset(fc::unsigned_int value, name finalizer); - - digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc); //get digest to sign from proposal data - - void reset_qc(fc::sha256 proposal_id); //reset current internal qc - - bool evaluate_quorum(extended_schedule es, fc::unsigned_int finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal); //evaluate quorum for a proposal - -/* name get_proposer(); - name get_leader(); - name get_incoming_leader(); //get incoming leader*/ - - bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); //check if quorum has been met over a proposal - - std::vector get_finalizers(); //get current finalizers set - - hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); //create new proposal message - hs_new_block_message new_block_candidate(block_id_type block_id); //create new block message - - void init(name id, base_pacemaker& pacemaker, std::set my_producers, bool info_logging, bool error_logging); //initialize qc object and add reference to the pacemaker - - bool am_i_proposer(); //check if I am the current proposer - bool am_i_leader(); //check if I am the current leader - bool am_i_finalizer(); //check if I am one of the current finalizers - - void process_proposal(hs_proposal_message msg); //handles proposal - void process_vote(hs_vote_message msg); //handles vote - void process_new_view(hs_new_view_message msg); //handles new view - void process_new_block(hs_new_block_message msg); //handles new block - - hs_vote_message sign_proposal(hs_proposal_message proposal, name finalizer); //sign proposal - - bool extends(fc::sha256 descendant, fc::sha256 ancestor); //verify that a proposal descends from another - - void on_beat(); //handler for pacemaker beat() - - void update_high_qc(eosio::chain::quorum_certificate high_qc); //check if update to our high qc is required - - void leader_rotation_check(); //check if leader rotation is required - - bool is_node_safe(hs_proposal_message proposal); //verify if a proposal should be signed - - std::vector get_qc_chain(fc::sha256 proposal_id); //get 3-phase proposal justification - - void send_hs_proposal_msg(hs_proposal_message msg); //send vote msg - void send_hs_vote_msg(hs_vote_message msg); //send proposal msg - void send_hs_new_view_msg(hs_new_view_message msg); //send new view msg - void send_hs_new_block_msg(hs_new_block_message msg); //send new block msg - - void on_hs_vote_msg(hs_vote_message msg); //vote msg event handler - void on_hs_proposal_msg(hs_proposal_message msg); //proposal msg event handler - void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler - - void update(hs_proposal_message proposal); //update internal state - void commit(hs_proposal_message proposal); //commit proposal (finality) - - void gc_proposals(uint64_t cutoff); //garbage collection of old proposals - - qc_chain(){ - //ilog("_high_qc : ${qc_id}", ("qc_id", _high_qc.proposal_id)); - - }; - - ~qc_chain(){ - - _proposal_store.get().clear(); - _proposal_store.get().clear(); - -/* if (_pacemaker == NULL) delete _pacemaker; - - _pacemaker = 0;*/ - - }; - - private : - - base_pacemaker* _pacemaker = NULL; - - }; -}} /// eosio::qc_chain \ No newline at end of file +#pragma once +#include +//#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +namespace eosio { namespace hotstuff { + + using boost::multi_index_container; + using namespace boost::multi_index; + + using namespace eosio::chain; + + //const uint32_t INTERUPT_TIMEOUT = 6; //sufficient timeout for new leader to be selected + + class qc_chain { + public: + + static void handle_eptr(std::exception_ptr eptr){ + try { + if (eptr) { + std::rethrow_exception(eptr); + } + } catch(const std::exception& e) { + ilog("Caught exception ${ex}" , ("ex", e.what())); + std::exit(0); + } + }; + + //todo : remove. bls12-381 key used for testing purposes + std::vector _seed = + { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22 }; + + fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); + + enum msg_type { + new_view = 1, + new_block = 2, + qc = 3, + vote = 4 + }; + + bool _chained_mode = false ; + + fc::sha256 _b_leaf = NULL_PROPOSAL_ID; + fc::sha256 _b_lock = NULL_PROPOSAL_ID; + fc::sha256 _b_exec = NULL_PROPOSAL_ID; + + fc::sha256 _b_finality_violation = NULL_PROPOSAL_ID; + + block_id_type _block_exec = NULL_BLOCK_ID; + + block_id_type _pending_proposal_block = NULL_BLOCK_ID; + + uint32_t _v_height; + + bool _log = true; + bool _errors = true; + + eosio::chain::quorum_certificate _high_qc; + eosio::chain::quorum_certificate _current_qc; + + eosio::chain::extended_schedule _schedule; + + std::set _my_producers; + + name _id; + + struct by_proposal_id{}; + struct by_proposal_height{}; + + typedef multi_index_container< + hs_proposal_message, + indexed_by< + hashed_unique< + tag, + BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) + >, + ordered_non_unique< + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) + > + > + > proposal_store_type; + + proposal_store_type _proposal_store; //internal proposals store + + uint32_t positive_bits_count(fc::unsigned_int value); + + fc::unsigned_int update_bitset(fc::unsigned_int value, name finalizer); + + digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc); //get digest to sign from proposal data + + void reset_qc(fc::sha256 proposal_id); //reset current internal qc + + bool evaluate_quorum(extended_schedule es, fc::unsigned_int finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal); //evaluate quorum for a proposal + +/* name get_proposer(); + name get_leader(); + name get_incoming_leader(); //get incoming leader*/ + + bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); //check if quorum has been met over a proposal + + std::vector get_finalizers(); //get current finalizers set + + hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); //create new proposal message + hs_new_block_message new_block_candidate(block_id_type block_id); //create new block message + + void init(name id, base_pacemaker& pacemaker, std::set my_producers, bool info_logging, bool error_logging); //initialize qc object and add reference to the pacemaker + + bool am_i_proposer(); //check if I am the current proposer + bool am_i_leader(); //check if I am the current leader + bool am_i_finalizer(); //check if I am one of the current finalizers + + void process_proposal(hs_proposal_message msg); //handles proposal + void process_vote(hs_vote_message msg); //handles vote + void process_new_view(hs_new_view_message msg); //handles new view + void process_new_block(hs_new_block_message msg); //handles new block + + hs_vote_message sign_proposal(hs_proposal_message proposal, name finalizer); //sign proposal + + bool extends(fc::sha256 descendant, fc::sha256 ancestor); //verify that a proposal descends from another + + void on_beat(); //handler for pacemaker beat() + + void update_high_qc(eosio::chain::quorum_certificate high_qc); //check if update to our high qc is required + + void leader_rotation_check(); //check if leader rotation is required + + bool is_node_safe(hs_proposal_message proposal); //verify if a proposal should be signed + + std::vector get_qc_chain(fc::sha256 proposal_id); //get 3-phase proposal justification + + void send_hs_proposal_msg(hs_proposal_message msg); //send vote msg + void send_hs_vote_msg(hs_vote_message msg); //send proposal msg + void send_hs_new_view_msg(hs_new_view_message msg); //send new view msg + void send_hs_new_block_msg(hs_new_block_message msg); //send new block msg + + void on_hs_vote_msg(hs_vote_message msg); //vote msg event handler + void on_hs_proposal_msg(hs_proposal_message msg); //proposal msg event handler + void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler + + void update(hs_proposal_message proposal); //update internal state + void commit(hs_proposal_message proposal); //commit proposal (finality) + + void gc_proposals(uint64_t cutoff); //garbage collection of old proposals + + qc_chain(){ + //ilog("_high_qc : ${qc_id}", ("qc_id", _high_qc.proposal_id)); + + }; + + ~qc_chain(){ + _proposal_store.get().clear(); + _proposal_store.get().clear(); + }; + + private: + + base_pacemaker* _pacemaker = nullptr; + + }; +}} /// eosio::qc_chain diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index e61d0e489a..0578846c5d 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -1,136 +1,120 @@ -#pragma once -#include -#include - -namespace eosio { namespace hotstuff { - - class test_pacemaker : public base_pacemaker { - - public: - - //class-specific functions - - class indexed_qc_chain{ - - public: - - name _name; - - bool _active = true; - - qc_chain* _qc_chain = NULL; //todo : use smart pointer - - uint64_t by_name()const{return _name.to_uint64_t();}; - - ~indexed_qc_chain(){ - - //if (_qc_chain == NULL) delete _qc_chain; - - _qc_chain = NULL; - - }; - - }; - - struct by_name_id{}; - - typedef multi_index_container< - indexed_qc_chain, - indexed_by< - ordered_unique< - tag, - BOOST_MULTI_INDEX_CONST_MEM_FUN(indexed_qc_chain, uint64_t, by_name) - > - > - > qc_chain_type; - - qc_chain_type _qcc_store; - - -/* void send_hs_proposal_msg(hs_proposal_message msg); - void send_hs_vote_msg(hs_vote_message msg); - void send_hs_new_block_msg(hs_new_block_message msg); - void send_hs_new_view_msg(hs_new_view_message msg);*/ - - using hotstuff_message = std::pair>; - - //void init(std::vector unique_replicas); - - void set_proposer(name proposer); - - void set_leader(name leader); - - void set_next_leader(name next_leader); - - void set_finalizers(std::vector finalizers); - - void set_current_block_id(block_id_type id); - - void set_quorum_threshold(uint32_t threshold); - - void add_message_to_queue(hotstuff_message msg); - - void pipe(std::vector messages); - - std::vector dispatch(std::string memo, int count); - std::vector dispatch(std::string memo); - - void activate(name replica); - void deactivate(name replica); - - //indexed_qc_chain get_qc_chain(name replica); - - ~test_pacemaker(){ - - _qcc_store.get().clear(); - - }; - - - //base_pacemaker interface functions - - name get_proposer(); - name get_leader(); - name get_next_leader(); - std::vector get_finalizers(); - - block_id_type get_current_block_id(); - - uint32_t get_quorum_threshold(); - - void assign_qc_chain(name name, qc_chain& qcc); - - void beat(); - - void send_hs_proposal_msg(name id, hs_proposal_message msg); - void send_hs_vote_msg(name id, hs_vote_message msg); - void send_hs_new_block_msg(name id, hs_new_block_message msg); - void send_hs_new_view_msg(name id, hs_new_view_message msg); - - void on_hs_vote_msg(name id, hs_vote_message msg); //confirmation msg event handler - void on_hs_proposal_msg(name id, hs_proposal_message msg); //consensus msg event handler - void on_hs_new_view_msg(name id, hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(name id, hs_new_block_message msg); //new block msg event handler - - std::vector _pending_message_queue; - - private : - - std::vector _message_queue; - - name _proposer; - name _leader; - name _next_leader; - - std::vector _finalizers; - - block_id_type _current_block_id; - - std::vector _unique_replicas; - - uint32_t _quorum_threshold = 15; //todo : calculate from schedule - - - }; - -}} \ No newline at end of file +#pragma once +#include +#include + +namespace eosio { namespace hotstuff { + + class test_pacemaker : public base_pacemaker { + public: + + //class-specific functions + + class indexed_qc_chain { + public: + name _name; + bool _active = true; + qc_chain* _qc_chain = nullptr; //todo : use smart pointer + + uint64_t by_name()const{return _name.to_uint64_t();}; + + ~indexed_qc_chain(){ + _qc_chain = nullptr; + }; + }; + + struct by_name_id{}; + + typedef multi_index_container< + indexed_qc_chain, + indexed_by< + ordered_unique< + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(indexed_qc_chain, uint64_t, by_name) + > + > + > qc_chain_type; + + qc_chain_type _qcc_store; + +/* void send_hs_proposal_msg(hs_proposal_message msg); + void send_hs_vote_msg(hs_vote_message msg); + void send_hs_new_block_msg(hs_new_block_message msg); + void send_hs_new_view_msg(hs_new_view_message msg);*/ + + using hotstuff_message = std::pair>; + + //void init(std::vector unique_replicas); + + void set_proposer(name proposer); + + void set_leader(name leader); + + void set_next_leader(name next_leader); + + void set_finalizers(std::vector finalizers); + + void set_current_block_id(block_id_type id); + + void set_quorum_threshold(uint32_t threshold); + + void add_message_to_queue(hotstuff_message msg); + + void pipe(std::vector messages); + + std::vector dispatch(std::string memo, int count); + std::vector dispatch(std::string memo); + + void activate(name replica); + void deactivate(name replica); + + //indexed_qc_chain get_qc_chain(name replica); + + ~test_pacemaker(){ + _qcc_store.get().clear(); + }; + + //base_pacemaker interface functions + + name get_proposer(); + name get_leader(); + name get_next_leader(); + std::vector get_finalizers(); + + block_id_type get_current_block_id(); + + uint32_t get_quorum_threshold(); + + void assign_qc_chain(name name, qc_chain& qcc); + + void beat(); + + void send_hs_proposal_msg(name id, hs_proposal_message msg); + void send_hs_vote_msg(name id, hs_vote_message msg); + void send_hs_new_block_msg(name id, hs_new_block_message msg); + void send_hs_new_view_msg(name id, hs_new_view_message msg); + + void on_hs_vote_msg(name id, hs_vote_message msg); //confirmation msg event handler + void on_hs_proposal_msg(name id, hs_proposal_message msg); //consensus msg event handler + void on_hs_new_view_msg(name id, hs_new_view_message msg); //new view msg event handler + void on_hs_new_block_msg(name id, hs_new_block_message msg); //new block msg event handler + + std::vector _pending_message_queue; + + private: + + std::vector _message_queue; + + name _proposer; + name _leader; + name _next_leader; + + std::vector _finalizers; + + block_id_type _current_block_id; + + std::vector _unique_replicas; + + uint32_t _quorum_threshold = 15; //todo : calculate from schedule + }; + +}} diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index d834d834f2..d757cc35a7 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -1,1252 +1,1013 @@ -#include - - -//todo list / notes : - -/* - - - -fork tests in unittests - - - -network plugin versioning - -handshake_message.network_version - -independant of protocol feature activation - - - -separate library for hotstuff (look at SHIP libray used by state history plugin ) - - -boost tests producer plugin test - - - -regression tests python framework as a base - - - -performance testing - - - - -*/ - - - -// -// complete proposer / leader differentiation -// integration with new bls implementation -// -// hotstuff as a library with its own tests (model on state history plugin + state_history library ) -// -// unit / integration tests -> producer_plugin + fork_tests tests as a model -// -// test deterministic sequence -// -// test non-replica participation -// test finality vioaltion -// test loss of liveness -// -// test split chain - -// -// store schedules and transition view height, and prune on commit - -// -// integration with fork_db / LIB overhaul -// -// integration with performance testing -// -// regression testing ci/cd -> python regression tests -// -// implement bitset for efficiency -// -// add APIs for proof data -// -// add election proposal in block header -// -// map proposers / finalizers / leader to new host functions -// -// support pause / resume producer -// -// keep track of proposals sent to peers -// -// allow syncing of proposals -// -// versioning of net protocol version -// -// protocol feature activation HOTSTUFF_CONSENSUS -// -// system contract update 1 -> allow BPs to register + prove their aggregate pub key. Allow existing BPs to unreg + reg without new aggregate key. Prevent new BPs from registering without proving aggregate pub key -// -// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available -// -// - - -namespace eosio { namespace hotstuff { - - - uint32_t qc_chain::positive_bits_count(fc::unsigned_int value){ - - boost::dynamic_bitset b(21, value); - - uint32_t count = 0; - - for (boost::dynamic_bitset<>::size_type i = 0; i < b.size(); i++){ - if (b[i]==true)count++; - } - - return count; - - } - - fc::unsigned_int qc_chain::update_bitset(fc::unsigned_int value, name finalizer){ - - /*ilog(" === update bitset ${value} ${finalizer}", - ("value", value) - ("finalizer", finalizer));*/ - - boost::dynamic_bitset b( 21, value ); - - vector finalizers = _pacemaker->get_finalizers(); - - for (size_t i = 0; i < finalizers.size();i++){ - if (finalizers[i] == finalizer){ - - b.flip(i); - - /*ilog(" === finalizer found ${finalizer} new value : ${value}", - ("finalizer", finalizer) - ("value", b.to_ulong()));*/ - - return b.to_ulong(); - } - } - - /*ilog(" *** finalizer not found ${finalizer}", - ("finalizer", finalizer));*/ - - throw std::runtime_error("finalizer not found"); - - } - - digest_type qc_chain::get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ - - digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); - digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); - - return h2; - - } - - std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ - - std::vector ret_arr; - - proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); - - b_2_itr = _proposal_store.get().find( proposal_id ); - if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); - if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); - - if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); - if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); - if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); - - return ret_arr; - - } - - hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { - - hs_proposal_message b_new; - - b_new.block_id = block_id; - b_new.parent_id = _b_leaf; - b_new.phase_counter = phase_counter; - - b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - - if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ - - std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - if (chain_length>=2){ - - auto itr = current_qc_chain.begin(); - - hs_proposal_message b2 = *itr; - itr++; - hs_proposal_message b1 = *itr; - - if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; - else { - - proposal_store_type::nth_index<0>::type::iterator p_itr; - - p_itr = _proposal_store.get().find( b1.parent_id ); - - b_new.final_on_qc = p_itr->final_on_qc; - - } - - } - - } - - b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); - - if (_log) ilog(" === ${id} creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", - ("id", _id) - ("block_num", b_new.block_num()) - ("phase_counter", b_new.phase_counter) - ("proposal_id", b_new.proposal_id) - ("parent_id", b_new.parent_id) - ("justify", b_new.justify.proposal_id)); - - return b_new; - - } - - void qc_chain::reset_qc(fc::sha256 proposal_id){ - - //if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); - _current_qc.proposal_id = proposal_id; - _current_qc.quorum_met = false; - _current_qc.active_finalizers = 0; - _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); - - } - - hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { - - hs_new_block_message b; - - b.block_id = block_id; - b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - - return b; - } - - bool qc_chain::evaluate_quorum(extended_schedule es, fc::unsigned_int finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ - - bool first = true; - - if (positive_bits_count(finalizers) < _pacemaker->get_quorum_threshold()){ - return false; - } - - boost::dynamic_bitset fb(21, finalizers.value); - - fc::crypto::blslib::bls_public_key agg_key; - - for (boost::dynamic_bitset<>::size_type i = 0; i < fb.size(); i++) { - - if (fb[i] == 1){ - //adding finalizer's key to the aggregate pub key - if (first) { - first = false; - agg_key = _private_key.get_public_key(); - } - else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); - } - - } - - fc::crypto::blslib::bls_signature justification_agg_sig; - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; - - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); - - return ok; - - } - - bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ - - if (qc.quorum_met == true ) { - return true; //skip evaluation if we've already verified quorum was met - } - else { - - //ilog(" === qc : ${qc}", ("qc", qc)); - - bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); - - qc.quorum_met = quorum_met; - - return qc.quorum_met ; - - } - - } - - void qc_chain::init(name id, base_pacemaker& pacemaker, std::set my_producers, bool info_logging, bool error_logging){ - - _id = id; - _log = info_logging; - _errors = error_logging; - - _pacemaker = &pacemaker; - - _my_producers = my_producers; - - _pacemaker->assign_qc_chain(id, *this); - - if (_log) ilog(" === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); - - //ilog(" === name ${name}", ("name", *itr)); - - } - - bool qc_chain::am_i_proposer(){ - - name proposer = _pacemaker->get_proposer(); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); - - if (prod_itr==_my_producers.end()) return false; - else return true; - - } - - bool qc_chain::am_i_leader(){ - - name leader = _pacemaker->get_leader(); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); - - if (prod_itr==_my_producers.end()) return false; - else return true; - - } - - bool qc_chain::am_i_finalizer(){ - - std::vector finalizers = _pacemaker->get_finalizers(); - - auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - name n = *mf_itr; - - auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f == n; }); - - if (prod_itr!=finalizers.end()) return true; - - mf_itr++; - - } - - return false; - - } - - hs_vote_message qc_chain::sign_proposal(hs_proposal_message proposal, name finalizer){ - - _v_height = proposal.get_height(); - - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer - - hs_vote_message v_msg = {proposal.proposal_id, finalizer, sig}; - - return v_msg; - - } - - void qc_chain::process_proposal(hs_proposal_message proposal){ - - auto start = fc::time_point::now(); - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID){ - - auto jp_itr = _proposal_store.get().find( proposal.justify.proposal_id ); - - if (jp_itr == _proposal_store.get().end()) { - if (_errors) ilog(" *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); - return; //can't recognize a proposal with an unknown justification - } - - } - - auto pid_itr = _proposal_store.get().find( proposal.proposal_id ); - - if (pid_itr != _proposal_store.get().end()) { - - if (_errors) ilog(" *** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); - - if (pid_itr->justify.proposal_id != proposal.justify.proposal_id) { - - if (_errors) ilog(" *** ${id} two identical proposals (${proposal_id}) have different justifications : ${justify_1} vs ${justify_2}", - ("id",_id) - ("proposal_id", proposal.proposal_id) - ("justify_1", pid_itr->justify.proposal_id) - ("justify_2", proposal.justify.proposal_id)); - - } - - return ; //already aware of proposal, nothing to do - - } - - auto hgt_itr = _proposal_store.get().lower_bound( proposal.get_height() ); - auto end_itr = _proposal_store.get().upper_bound( proposal.get_height() ); - - //height is not necessarily unique, so we iterate over all prior proposals at this height - while (hgt_itr != end_itr) { - if (_errors) ilog(" *** ${id} received a different proposal at the same height (${block_num}, ${phase_counter})", - ("id",_id) - ("block_num", hgt_itr->block_num()) - ("phase_counter", hgt_itr->phase_counter)); - - if (_errors) ilog(" *** Proposal #1 : ${proposal_id_1} Proposal #2 : ${proposal_id_2}", - ("proposal_id_1", hgt_itr->proposal_id) - ("proposal_id_2", proposal.proposal_id)); - - hgt_itr++; - - } - - - if (_log) ilog(" === ${id} received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id) - ("parent_id", proposal.parent_id) - ("justify", proposal.justify.proposal_id)); - - _proposal_store.insert(proposal); //new proposal - - //if I am a finalizer for this proposal and the safenode predicate for a possible vote is true, sign - bool am_finalizer = am_i_finalizer(); - bool node_safe = is_node_safe(proposal); - - bool signature_required = am_finalizer && node_safe; - - if (signature_required){ - - //iterate over all my finalizers and sign / broadcast for each that is in the schedule - std::vector finalizers = _pacemaker->get_finalizers(); - - auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - auto prod_itr = std::find(finalizers.begin(), finalizers.end(), *mf_itr); - - if (prod_itr!=finalizers.end()) { - - hs_vote_message v_msg = sign_proposal(proposal, *prod_itr); - -/* if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id));*/ - - send_hs_vote_msg(v_msg); - - }; - - mf_itr++; - - } - - } -/* else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id));*/ - - - //update internal state - update(proposal); - - //check for leader change - leader_rotation_check(); - - auto total_time = fc::time_point::now() - start; - - //if (_log) ilog(" ... process_proposal() total time : ${total_time}", ("total_time", total_time)); - - } - - void qc_chain::process_vote(hs_vote_message vote){ - - auto start = fc::time_point::now(); - - //todo : check for duplicate or invalid vote. We will return in either case, but keep proposals for evidence of double signing - - bool am_leader = am_i_leader(); //am I leader? - - if(!am_leader) return; - - //ilog(" === Process vote from ${finalizer} : current bitset ${value}" , ("finalizer", vote.finalizer)("value", _current_qc.active_finalizers)); - - //only leader need to take action on votes - - if (vote.proposal_id != _current_qc.proposal_id) return; - - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); - - if (p_itr==_proposal_store.get().end()){ - if (_errors) ilog(" *** ${id} couldn't find proposal", ("id",_id)); - - if (_errors) ilog(" *** ${id} vote : ${vote}", ("vote", vote)("id",_id)); - - return; - } - - bool quorum_met = _current_qc.quorum_met; //check if quorum already met - - //if quorum is already met, we don't need to do anything else. Otherwise, we aggregate the signature - if (!quorum_met){ - - if (_current_qc.active_finalizers>0) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); - else _current_qc.active_agg_sig = vote.sig; - - _current_qc.active_finalizers = update_bitset(_current_qc.active_finalizers, vote.finalizer); - - quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); - - if (quorum_met){ - - _current_qc.quorum_met = true; - - if (_log) ilog(" === ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", - ("block_num", p_itr->block_num()) - ("phase_counter", p_itr->phase_counter) - ("proposal_id", vote.proposal_id) - ("id", _id)); - - //ilog(" === update_high_qc : _current_qc ==="); - update_high_qc(_current_qc); - - //check for leader change - leader_rotation_check(); - - //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet - if (_chained_mode==false && p_itr->phase_counter<3){ - - //if (_log) ilog(" === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); - - hs_proposal_message proposal_candidate; - - if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); - else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); - - reset_qc(proposal_candidate.proposal_id); - - //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); - _pending_proposal_block = NULL_BLOCK_ID; - - send_hs_proposal_msg(proposal_candidate); - - _b_leaf = proposal_candidate.proposal_id; - - //if (_log) ilog(" === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); - - } - - } - - } - - auto total_time = fc::time_point::now() - start; - - //if (_log) ilog(" ... process_vote() total time : ${total_time}", ("total_time", total_time)); - - } - - void qc_chain::process_new_view(hs_new_view_message new_view){ - - //if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", new_view.high_qc)("id", _id)); - update_high_qc(new_view.high_qc); - - } - - void qc_chain::process_new_block(hs_new_block_message msg){ - - //ilog(" === Process new block ==="); - - } - - void qc_chain::send_hs_proposal_msg(hs_proposal_message msg){ - - //ilog(" === broadcast_hs_proposal ==="); - - //hs_proposal_message_ptr ptr = std::make_shared(msg); - - _pacemaker->send_hs_proposal_msg(_id, msg); - - process_proposal(msg); - - } - - - void qc_chain::send_hs_vote_msg(hs_vote_message msg){ - - //ilog(" === broadcast_hs_vote ==="); - - //hs_vote_message_ptr ptr = std::make_shared(msg); - - _pacemaker->send_hs_vote_msg(_id, msg); - - process_vote(msg); - - } - - void qc_chain::send_hs_new_view_msg(hs_new_view_message msg){ - - //ilog(" === broadcast_hs_new_view ==="); - - //hs_new_view_message_ptr ptr = std::make_shared(msg); - - _pacemaker->send_hs_new_view_msg(_id, msg); - - } - - void qc_chain::send_hs_new_block_msg(hs_new_block_message msg){ - - //ilog(" === broadcast_hs_new_block ==="); - - //hs_new_block_message_ptr ptr = std::make_shared(msg); - - _pacemaker->send_hs_new_block_msg(_id, msg); - - } - - //extends predicate - bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ - - //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified - - proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); - - uint32_t counter = 0; - - while (itr!=_proposal_store.get().end()){ - - itr = _proposal_store.get().find(itr->parent_id ); - - if (itr->proposal_id == ancestor){ - if (counter>25) { - if (_errors) ilog(" *** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); - - } - return true; - } - - counter++; - - } - - if (_errors) ilog(" *** ${id} extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", - ("id",_id) - ("d_proposal_id", descendant) - ("a_proposal_id", ancestor)); - - return false; - - } - - void qc_chain::on_beat(){ -std::exception_ptr eptr; -try{ - - auto start = fc::time_point::now(); - - //if (_log) ilog(" === ${id} on beat === ", ("id", _id)); - - //std::lock_guard g( this-> _hotstuff_state_mutex ); - - name current_producer = _pacemaker->get_leader(); - - if (current_producer == "eosio"_n) return; - - block_id_type current_block_id = _pacemaker->get_current_block_id(); - - //ilog(" === qc chain on_beat ${my_producers}", ("my_producers", _my_producers)); - - bool am_proposer = am_i_proposer(); - - bool am_leader = am_i_leader(); - - //if (_log) ilog(" === ${id} am_proposer = ${am_proposer}", ("am_proposer", am_proposer)("id", _id)); - //if (_log) ilog(" === ${id} am_leader = ${am_leader}", ("am_leader", am_leader)("id", _id)); - - if (!am_proposer && !am_leader){ - - return; //nothing to do - - } - - //if I am the leader - if (am_leader){ - - //if I'm not also the proposer, perform block validation as required - if (!am_proposer){ - - //todo : extra validation? - - } - - - if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ -/* - if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", - ("id", _id) - ("proposal_id", _current_qc.proposal_id) - ("quorum_met", _current_qc.quorum_met)); - - if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", current_block_id));*/ - _pending_proposal_block = current_block_id; - - } - else { - -/* if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", - ("id", _id) - ("proposal_id", _current_qc.proposal_id) - ("quorum_met", _current_qc.quorum_met)); -*/ - hs_proposal_message proposal_candidate = new_proposal_candidate(current_block_id, 0 ); - - reset_qc(proposal_candidate.proposal_id); - - //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (on_beat)", ("id", _id)); - - _pending_proposal_block = NULL_BLOCK_ID; - - send_hs_proposal_msg(proposal_candidate); - - _b_leaf = proposal_candidate.proposal_id; - - //if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); - - } - - } - else { - - //if I'm only a proposer and not the leader, I send a new block message - - hs_new_block_message block_candidate = new_block_candidate(current_block_id); - - //ilog(" === broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); - - send_hs_new_block_msg(block_candidate); - - } - - auto total_time = fc::time_point::now() - start; - - //if (_log) ilog(" ... on_beat() total time : ${total_time}", ("total_time", total_time)); - - //ilog(" === end of on_beat"); -} -catch (...){ - ilog("error during on_beat"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ - - //ilog(" === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); - - // if new high QC is higher than current, update to new - - - if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ - - _high_qc = high_qc; - _b_leaf = _high_qc.proposal_id; - - //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); - - } - else { - - proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; - proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; - - old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); - new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); - - if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); - if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); - - - if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ - - bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); - - if (quorum_met){ - - high_qc.quorum_met = true; - - //ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); - - _high_qc = high_qc; - _b_leaf = _high_qc.proposal_id; - - //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); - - } - - } - - } - - } - - void qc_chain::leader_rotation_check(){ - - //verify if leader changed - - name current_leader = _pacemaker->get_leader() ; - name next_leader = _pacemaker->get_next_leader() ; - - if (current_leader != next_leader){ - - if (_log) ilog(" /// ${id} rotating leader : ${old_leader} -> ${new_leader} ", - ("id", _id) - ("old_leader", current_leader) - ("new_leader", next_leader)); - - //leader changed, we send our new_view message - - reset_qc(NULL_PROPOSAL_ID); - - //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); - - _pending_proposal_block = NULL_BLOCK_ID; - - hs_new_view_message new_view; - - new_view.high_qc = _high_qc; - - send_hs_new_view_msg(new_view); - } - - - } - - //safenode predicate - bool qc_chain::is_node_safe(hs_proposal_message proposal){ - - //ilog(" === is_node_safe ==="); - - bool monotony_check = false; - bool safety_check = false; - bool liveness_check = false; - bool final_on_qc_check = false; - - fc::sha256 upcoming_commit; - - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated - else { - - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - if (chain_length>=2){ - - auto itr = current_qc_chain.begin(); - - hs_proposal_message b2 = *itr; - itr++; - hs_proposal_message b1 = *itr; - - if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; - else { - - proposal_store_type::nth_index<0>::type::iterator p_itr; - - p_itr = _proposal_store.get().find( b1.parent_id ); - - upcoming_commit = p_itr->final_on_qc; - - } - - } - - //abstracted [...] - if (upcoming_commit == proposal.final_on_qc){ - final_on_qc_check = true; - } - - } - - if (proposal.get_height() > _v_height){ - monotony_check = true; - } - - if (_b_lock != NULL_PROPOSAL_ID){ - - //Safety check : check if this proposal extends the chain I'm locked on - if (extends(proposal.proposal_id, _b_lock)){ - safety_check = true; - } - - //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated - else { - - proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); - proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); - - if (prop_justification->get_height() > b_lock->get_height()){ - liveness_check = true; - } - } - - } - else { - - //if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); - - //if we're not locked on anything, means the protocol just activated or chain just launched - liveness_check = true; - safety_check = true; - } - -/* ilog(" === final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", - ("final_on_qc_check", final_on_qc_check) - ("monotony_check", monotony_check) - ("liveness_check", liveness_check) - ("safety_check", safety_check));*/ - - bool node_is_safe = final_on_qc_check && monotony_check && (liveness_check || safety_check); - - if (!node_is_safe) { - - if (_errors) ilog(" *** node is NOT safe. Checks : final_on_qc: ${final_on_qc}, monotony_check: ${monotony_check}, liveness_check: ${liveness_check}, safety_check: ${safety_check})", - ("final_on_qc_check",final_on_qc_check) - ("monotony_check",monotony_check) - ("liveness_check",liveness_check) - ("safety_check",safety_check)); - - } - - return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully - - } - - //on proposal received, called from network thread - void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ -std::exception_ptr eptr; -try{ - - //ilog(" === ${id} qc on_hs_proposal_msg ===", ("id", _id)); - - //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_proposal(msg); - - //ilog(" === end of on_hs_proposal_msg"); -} -catch (...){ - if (_errors) ilog(" *** ${id} error during on_hs_proposal_msg", ("id",_id)); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on vote received, called from network thread - void qc_chain::on_hs_vote_msg(hs_vote_message msg){ -std::exception_ptr eptr; -try{ - - //ilog(" === ${id} qc on_hs_vote_msg ===", ("id", _id)); - - //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_vote(msg); - - //ilog(" === end of on_hs_vote_msg"); - } -catch (...){ - if (_errors) ilog(" *** ${id} error during on_hs_vote_msg", ("id",_id)); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on new view received, called from network thread - void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ -std::exception_ptr eptr; -try{ - - //ilog(" === ${id} qc on_hs_new_view_msg ===", ("id", _id)); - - //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_new_view(msg); - - //ilog(" === end of on_hs_new_view_msg"); -} -catch (...){ - if (_errors) ilog(" *** ${id} error during on_hs_new_view_msg", ("id",_id)); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on new block received, called from network thread - void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ -std::exception_ptr eptr; -try{ - - //ilog(" === ${id} qc on_hs_new_block_msg ===", ("id", _id)); - - //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_new_block(msg); - - //ilog(" === end of on_hs_new_block_msg"); -} -catch (...){ - if (_errors) ilog(" *** ${id} error during on_hs_new_block_msg", ("id",_id)); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - void qc_chain::update(hs_proposal_message proposal){ - - //ilog(" === update internal state ==="); - - //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ - if (_log) ilog(" === ${id} proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)("id", _id)); - return; - } - - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock); - - //ilog(" === update_high_qc : proposal.justify ==="); - update_high_qc(proposal.justify); - - if (chain_length<1){ - if (_log) ilog(" === ${id} qc chain length is 0", ("id", _id)); - return; - } - - auto itr = current_qc_chain.begin(); - hs_proposal_message b_2 = *itr; - - if (chain_length<2){ - if (_log) ilog(" === ${id} qc chain length is 1", ("id", _id)); - return; - } - - itr++; - - hs_proposal_message b_1 = *itr; - - //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock - -/* if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height} b_lock height ${b_lock_height}", - ("id", _id) - ("_b_lock", _b_lock) - ("b_1_height", b_1.block_num()) - ("b_1_phase", b_1.phase_counter) - ("b_lock_height", b_lock->block_num()) - ("b_lock_phase", b_lock->phase_counter));*/ - - if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ - - //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); - _b_lock = b_1.proposal_id; //commit phase on b1 - - //if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); - - } - - if (chain_length<3){ - if (_log) ilog(" === ${id} qc chain length is 2",("id", _id)); - return; - } - - itr++; - - hs_proposal_message b = *itr; - -/* ilog(" === direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", - ("b_2.parent_id",b_2.parent_id) - ("b_1.proposal_id", b_1.proposal_id) - ("b_1.parent_id", b_1.parent_id) - ("b.proposal_id", b.proposal_id));*/ - - //direct parent relationship verification - if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ - - if (_b_exec!= NULL_PROPOSAL_ID){ - - proposal_store_type::nth_index<0>::type::iterator b_exec = _proposal_store.get().find( _b_exec); - - if (b_exec->get_height() >= b.get_height() && b_exec->proposal_id != b.proposal_id){ - - if (_errors) ilog(" *** ${id} finality violation detected at height ${block_num}, phase : ${phase}. Proposal ${proposal_id_1} conflicts with ${proposal_id_2}", - ("id", _id) - ("block_num", b.block_num()) - ("phase", b.phase_counter) - ("proposal_id_1", b.proposal_id) - ("proposal_id_2", b_exec->proposal_id)); - - _b_finality_violation = b.proposal_id; - - //protocol failure - - return; - - } - - } - - commit(b); - - //ilog(" === last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); - - _b_exec = b.proposal_id; //decide phase on b - _block_exec = b.block_id; - - gc_proposals( b.get_height()-1); - - } - else { - - if (_errors) ilog(" *** ${id} could not verify direct parent relationship", ("id",_id)); - - if (_errors) ilog(" *** b_2 ${b_2}", ("b_2", b_2)); - if (_errors) ilog(" *** b_1 ${b_1}", ("b_1", b_1)); - if (_errors) ilog(" *** b ${b}", ("b", b)); - - } - - - } - - void qc_chain::gc_proposals(uint64_t cutoff){ - - //ilog(" === garbage collection on old data"); - - auto end_itr = _proposal_store.get().upper_bound(cutoff); - - while (_proposal_store.get().begin() != end_itr){ - - auto itr = _proposal_store.get().begin(); - -/* if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", - ("id", _id) - ("block_num", itr->block_num()) - ("phase_counter", itr->phase_counter) - ("block_id", itr->block_id) - ("proposal_id", itr->proposal_id));*/ - - _proposal_store.get().erase(itr); - - - } - - } - - void qc_chain::commit(hs_proposal_message proposal){ - -/* ilog(" === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", proposal.block_num()) - ("proposal_id", proposal.proposal_id) - ("block_id", proposal.block_id) - ("phase_counter", proposal.phase_counter) - ("parent_id", proposal.parent_id)); - */ - bool exec_height_check = false; - - proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); - -/* ilog(" === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", last_exec_prop->block_num()) - ("proposal_id", last_exec_prop->proposal_id) - ("block_id", last_exec_prop->block_id) - ("phase_counter", last_exec_prop->phase_counter) - ("parent_id", last_exec_prop->parent_id));*/ - -/* ilog(" *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", - ("proposal_id_1", last_exec_prop->block_num()) - ("phase_counter_1", last_exec_prop->phase_counter) - ("proposal_id_2", proposal.block_num()) - ("phase_counter_2", proposal.phase_counter));*/ - - if (_b_exec==NULL_PROPOSAL_ID){ - exec_height_check = true; - } - else exec_height_check = last_exec_prop->get_height() < proposal.get_height(); - - if (exec_height_check){ - - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); - - if (p_itr != _proposal_store.get().end()){ - - //ilog(" === recursively committing" ); - - commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first - - } - - //Execute commands [...] - - if (_log) ilog(" === ${id} committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("block_id", proposal.block_id) - ("proposal_id", proposal.proposal_id)); - } - - -/* else { - if (_errors) ilog(" *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id)); - }*/ - - - } - -}} - - +#include + +/* + + Todo list / notes: + - fork tests in unittests + - network plugin versioning + - handshake_message.network_version + - independant of protocol feature activation + - separate library for hotstuff (look at SHIP libray used by state history plugin ) + - boost tests producer plugin test + - regression tests python framework as a base + - performance testing + - complete proposer / leader differentiation + - integration with new bls implementation + - hotstuff as a library with its own tests (model on state history plugin + state_history library ) + - unit / integration tests -> producer_plugin + fork_tests tests as a model + - test deterministic sequence + - test non-replica participation + - test finality vioaltion + - test loss of liveness + - test split chain + - store schedules and transition view height, and prune on commit + - integration with fork_db / LIB overhaul + - integration with performance testing + - regression testing ci/cd -> python regression tests + - implement bitset for efficiency + - add APIs for proof data + - add election proposal in block header + - map proposers / finalizers / leader to new host functions + - support pause / resume producer + - keep track of proposals sent to peers + - allow syncing of proposals + - versioning of net protocol version + - protocol feature activation HOTSTUFF_CONSENSUS + - system contract update 1 + -- allow BPs to register + prove their aggregate pub key. + -- Allow existing BPs to unreg + reg without new aggregate key. + -- Prevent new BPs from registering without proving aggregate pub key + - system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) + -- skip BPs without a bls key in the selection, new host functions are available +*/ + +namespace eosio { namespace hotstuff { + + uint32_t qc_chain::positive_bits_count(fc::unsigned_int value){ + boost::dynamic_bitset b(21, value); + uint32_t count = 0; + for (boost::dynamic_bitset<>::size_type i = 0; i < b.size(); i++){ + if (b[i]==true)count++; + } + return count; + } + + fc::unsigned_int qc_chain::update_bitset(fc::unsigned_int value, name finalizer){ + /*ilog(" === update bitset ${value} ${finalizer}", + ("value", value) + ("finalizer", finalizer));*/ + + boost::dynamic_bitset b( 21, value ); + vector finalizers = _pacemaker->get_finalizers(); + for (size_t i = 0; i < finalizers.size();i++){ + if (finalizers[i] == finalizer){ + b.flip(i); + + /*ilog(" === finalizer found ${finalizer} new value : ${value}", + ("finalizer", finalizer) + ("value", b.to_ulong()));*/ + + return b.to_ulong(); + } + } + + /*ilog(" *** finalizer not found ${finalizer}", + ("finalizer", finalizer));*/ + + throw std::runtime_error("finalizer not found"); + } + + digest_type qc_chain::get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ + digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); + digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); + return h2; + } + + std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ + std::vector ret_arr; + proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); + proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); + b_2_itr = _proposal_store.get().find( proposal_id ); + if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); + if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); + if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); + if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); + if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); + return ret_arr; + } + + hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { + hs_proposal_message b_new; + b_new.block_id = block_id; + b_new.parent_id = _b_leaf; + b_new.phase_counter = phase_counter; + b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ + std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + if (chain_length>=2){ + auto itr = current_qc_chain.begin(); + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; + else { + proposal_store_type::nth_index<0>::type::iterator p_itr; + p_itr = _proposal_store.get().find( b1.parent_id ); + b_new.final_on_qc = p_itr->final_on_qc; + } + } + } + + b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); + + if (_log) ilog(" === ${id} creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + ("id", _id) + ("block_num", b_new.block_num()) + ("phase_counter", b_new.phase_counter) + ("proposal_id", b_new.proposal_id) + ("parent_id", b_new.parent_id) + ("justify", b_new.justify.proposal_id)); + + return b_new; + } + + void qc_chain::reset_qc(fc::sha256 proposal_id){ + //if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); + _current_qc.proposal_id = proposal_id; + _current_qc.quorum_met = false; + _current_qc.active_finalizers = 0; + _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); + } + + hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { + hs_new_block_message b; + b.block_id = block_id; + b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + return b; + } + + bool qc_chain::evaluate_quorum(extended_schedule es, fc::unsigned_int finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ + + bool first = true; + + if (positive_bits_count(finalizers) < _pacemaker->get_quorum_threshold()){ + return false; + } + + boost::dynamic_bitset fb(21, finalizers.value); + fc::crypto::blslib::bls_public_key agg_key; + + for (boost::dynamic_bitset<>::size_type i = 0; i < fb.size(); i++) { + if (fb[i] == 1){ + //adding finalizer's key to the aggregate pub key + if (first) { + first = false; + agg_key = _private_key.get_public_key(); + } + else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); + } + } + + fc::crypto::blslib::bls_signature justification_agg_sig; + + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; + + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); + + return ok; + } + + bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ + + if (qc.quorum_met == true ) { + return true; //skip evaluation if we've already verified quorum was met + } + else { + //ilog(" === qc : ${qc}", ("qc", qc)); + + bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); + + qc.quorum_met = quorum_met; + + return qc.quorum_met; + } + } + + void qc_chain::init(name id, base_pacemaker& pacemaker, std::set my_producers, bool info_logging, bool error_logging){ + + _id = id; + _log = info_logging; + _errors = error_logging; + _pacemaker = &pacemaker; + _my_producers = my_producers; + _pacemaker->assign_qc_chain(id, *this); + + if (_log) ilog(" === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); + + //ilog(" === name ${name}", ("name", *itr)); + } + + bool qc_chain::am_i_proposer(){ + name proposer = _pacemaker->get_proposer(); + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); + if (prod_itr==_my_producers.end()) return false; + else return true; + } + + bool qc_chain::am_i_leader(){ + name leader = _pacemaker->get_leader(); + auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); + if (prod_itr==_my_producers.end()) return false; + else return true; + } + + bool qc_chain::am_i_finalizer(){ + std::vector finalizers = _pacemaker->get_finalizers(); + auto mf_itr = _my_producers.begin(); + while(mf_itr!=_my_producers.end()){ + name n = *mf_itr; + auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f == n; }); + if (prod_itr!=finalizers.end()) return true; + mf_itr++; + } + return false; + } + + hs_vote_message qc_chain::sign_proposal(hs_proposal_message proposal, name finalizer){ + + _v_height = proposal.get_height(); + + digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); + + std::vector h = std::vector(digest.data(), digest.data() + 32); + + fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer + + hs_vote_message v_msg = {proposal.proposal_id, finalizer, sig}; + return v_msg; + } + + void qc_chain::process_proposal(hs_proposal_message proposal){ + + //auto start = fc::time_point::now(); + + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID){ + + auto jp_itr = _proposal_store.get().find( proposal.justify.proposal_id ); + + if (jp_itr == _proposal_store.get().end()) { + if (_errors) ilog(" *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); + return; //can't recognize a proposal with an unknown justification + } + } + + auto pid_itr = _proposal_store.get().find( proposal.proposal_id ); + + if (pid_itr != _proposal_store.get().end()) { + + if (_errors) ilog(" *** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); + + if (pid_itr->justify.proposal_id != proposal.justify.proposal_id) { + + if (_errors) ilog(" *** ${id} two identical proposals (${proposal_id}) have different justifications : ${justify_1} vs ${justify_2}", + ("id",_id) + ("proposal_id", proposal.proposal_id) + ("justify_1", pid_itr->justify.proposal_id) + ("justify_2", proposal.justify.proposal_id)); + + } + + return; //already aware of proposal, nothing to do + } + + auto hgt_itr = _proposal_store.get().lower_bound( proposal.get_height() ); + auto end_itr = _proposal_store.get().upper_bound( proposal.get_height() ); + + //height is not necessarily unique, so we iterate over all prior proposals at this height + while (hgt_itr != end_itr) { + if (_errors) ilog(" *** ${id} received a different proposal at the same height (${block_num}, ${phase_counter})", + ("id",_id) + ("block_num", hgt_itr->block_num()) + ("phase_counter", hgt_itr->phase_counter)); + + if (_errors) ilog(" *** Proposal #1 : ${proposal_id_1} Proposal #2 : ${proposal_id_2}", + ("proposal_id_1", hgt_itr->proposal_id) + ("proposal_id_2", proposal.proposal_id)); + + hgt_itr++; + } + + if (_log) ilog(" === ${id} received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id) + ("parent_id", proposal.parent_id) + ("justify", proposal.justify.proposal_id)); + + _proposal_store.insert(proposal); //new proposal + + //if I am a finalizer for this proposal and the safenode predicate for a possible vote is true, sign + bool am_finalizer = am_i_finalizer(); + bool node_safe = is_node_safe(proposal); + bool signature_required = am_finalizer && node_safe; + + if (signature_required){ + + //iterate over all my finalizers and sign / broadcast for each that is in the schedule + std::vector finalizers = _pacemaker->get_finalizers(); + + auto mf_itr = _my_producers.begin(); + + while(mf_itr!=_my_producers.end()){ + + auto prod_itr = std::find(finalizers.begin(), finalizers.end(), *mf_itr); + + if (prod_itr!=finalizers.end()) { + + hs_vote_message v_msg = sign_proposal(proposal, *prod_itr); + +/* if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id));*/ + + send_hs_vote_msg(v_msg); + + }; + + mf_itr++; + } + } +/* else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id));*/ + + + //update internal state + update(proposal); + + //check for leader change + leader_rotation_check(); + + //auto total_time = fc::time_point::now() - start; + //if (_log) ilog(" ... process_proposal() total time : ${total_time}", ("total_time", total_time)); + } + + void qc_chain::process_vote(hs_vote_message vote){ + + //auto start = fc::time_point::now(); + + //todo : check for duplicate or invalid vote. We will return in either case, but keep proposals for evidence of double signing + + bool am_leader = am_i_leader(); //am I leader? + + if(!am_leader) return; + + //ilog(" === Process vote from ${finalizer} : current bitset ${value}" , ("finalizer", vote.finalizer)("value", _current_qc.active_finalizers)); + + //only leader need to take action on votes + + if (vote.proposal_id != _current_qc.proposal_id) return; + + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); + + if (p_itr==_proposal_store.get().end()){ + if (_errors) ilog(" *** ${id} couldn't find proposal", ("id",_id)); + if (_errors) ilog(" *** ${id} vote : ${vote}", ("vote", vote)("id",_id)); + return; + } + + bool quorum_met = _current_qc.quorum_met; //check if quorum already met + + //if quorum is already met, we don't need to do anything else. Otherwise, we aggregate the signature + if (!quorum_met){ + + if (_current_qc.active_finalizers>0) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); + else _current_qc.active_agg_sig = vote.sig; + + _current_qc.active_finalizers = update_bitset(_current_qc.active_finalizers, vote.finalizer); + + quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); + + if (quorum_met){ + + _current_qc.quorum_met = true; + + if (_log) ilog(" === ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", + ("block_num", p_itr->block_num()) + ("phase_counter", p_itr->phase_counter) + ("proposal_id", vote.proposal_id) + ("id", _id)); + + //ilog(" === update_high_qc : _current_qc ==="); + update_high_qc(_current_qc); + + //check for leader change + leader_rotation_check(); + + //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet + if (_chained_mode==false && p_itr->phase_counter<3){ + + //if (_log) ilog(" === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); + + hs_proposal_message proposal_candidate; + + if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); + else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); + + reset_qc(proposal_candidate.proposal_id); + + //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); + _pending_proposal_block = NULL_BLOCK_ID; + + send_hs_proposal_msg(proposal_candidate); + + _b_leaf = proposal_candidate.proposal_id; + + //if (_log) ilog(" === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); + } + } + } + + //auto total_time = fc::time_point::now() - start; + //if (_log) ilog(" ... process_vote() total time : ${total_time}", ("total_time", total_time)); + } + + void qc_chain::process_new_view(hs_new_view_message new_view){ + //if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", new_view.high_qc)("id", _id)); + update_high_qc(new_view.high_qc); + } + + void qc_chain::process_new_block(hs_new_block_message msg){ + //ilog(" === Process new block ==="); + } + + void qc_chain::send_hs_proposal_msg(hs_proposal_message msg){ + //ilog(" === broadcast_hs_proposal ==="); + //hs_proposal_message_ptr ptr = std::make_shared(msg); + _pacemaker->send_hs_proposal_msg(_id, msg); + process_proposal(msg); + } + + void qc_chain::send_hs_vote_msg(hs_vote_message msg){ + //ilog(" === broadcast_hs_vote ==="); + //hs_vote_message_ptr ptr = std::make_shared(msg); + _pacemaker->send_hs_vote_msg(_id, msg); + process_vote(msg); + } + + void qc_chain::send_hs_new_view_msg(hs_new_view_message msg){ + //ilog(" === broadcast_hs_new_view ==="); + //hs_new_view_message_ptr ptr = std::make_shared(msg); + _pacemaker->send_hs_new_view_msg(_id, msg); + } + + void qc_chain::send_hs_new_block_msg(hs_new_block_message msg){ + //ilog(" === broadcast_hs_new_block ==="); + //hs_new_block_message_ptr ptr = std::make_shared(msg); + _pacemaker->send_hs_new_block_msg(_id, msg); + } + + //extends predicate + bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ + + //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified + + proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); + + uint32_t counter = 0; + + while (itr!=_proposal_store.get().end()){ + itr = _proposal_store.get().find(itr->parent_id ); + if (itr->proposal_id == ancestor){ + if (counter>25) { + if (_errors) ilog(" *** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); + } + return true; + } + counter++; + } + + if (_errors) ilog(" *** ${id} extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", + ("id",_id) + ("d_proposal_id", descendant) + ("a_proposal_id", ancestor)); + + return false; + } + + void qc_chain::on_beat(){ + std::exception_ptr eptr; + try{ + //auto start = fc::time_point::now(); + + //if (_log) ilog(" === ${id} on beat === ", ("id", _id)); + + //std::lock_guard g( this-> _hotstuff_state_mutex ); + + name current_producer = _pacemaker->get_leader(); + + if (current_producer == "eosio"_n) return; + + block_id_type current_block_id = _pacemaker->get_current_block_id(); + + //ilog(" === qc chain on_beat ${my_producers}", ("my_producers", _my_producers)); + + bool am_proposer = am_i_proposer(); + + bool am_leader = am_i_leader(); + + //if (_log) ilog(" === ${id} am_proposer = ${am_proposer}", ("am_proposer", am_proposer)("id", _id)); + //if (_log) ilog(" === ${id} am_leader = ${am_leader}", ("am_leader", am_leader)("id", _id)); + + if (!am_proposer && !am_leader){ + return; //nothing to do + } + + //if I am the leader + if (am_leader){ + + //if I'm not also the proposer, perform block validation as required + if (!am_proposer){ + + //todo : extra validation? + + } + + if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ +/* + if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", + ("id", _id) + ("proposal_id", _current_qc.proposal_id) + ("quorum_met", _current_qc.quorum_met)); + + if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", current_block_id));*/ + _pending_proposal_block = current_block_id; + + } + else { + +/* if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", + ("id", _id) + ("proposal_id", _current_qc.proposal_id) + ("quorum_met", _current_qc.quorum_met)); +*/ + hs_proposal_message proposal_candidate = new_proposal_candidate(current_block_id, 0 ); + + reset_qc(proposal_candidate.proposal_id); + + //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (on_beat)", ("id", _id)); + + _pending_proposal_block = NULL_BLOCK_ID; + + send_hs_proposal_msg(proposal_candidate); + + _b_leaf = proposal_candidate.proposal_id; + + //if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); + } + } + else { + + //if I'm only a proposer and not the leader, I send a new block message + + hs_new_block_message block_candidate = new_block_candidate(current_block_id); + + //ilog(" === broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); + + send_hs_new_block_msg(block_candidate); + } + + //auto total_time = fc::time_point::now() - start; + //if (_log) ilog(" ... on_beat() total time : ${total_time}", ("total_time", total_time)); + //ilog(" === end of on_beat"); + } + catch (...){ + ilog("error during on_beat"); + eptr = std::current_exception(); // capture + } + handle_eptr(eptr); + } + + void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ + + //ilog(" === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); + // if new high QC is higher than current, update to new + + if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ + + _high_qc = high_qc; + _b_leaf = _high_qc.proposal_id; + + //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); + } + else { + + proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; + proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; + + old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); + new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); + + if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); + if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); + + if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ + + bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); + + if (quorum_met){ + + high_qc.quorum_met = true; + + //ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); + + _high_qc = high_qc; + _b_leaf = _high_qc.proposal_id; + + //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); + } + } + } + } + + void qc_chain::leader_rotation_check(){ + + //verify if leader changed + + name current_leader = _pacemaker->get_leader() ; + name next_leader = _pacemaker->get_next_leader() ; + + if (current_leader != next_leader){ + + if (_log) ilog(" /// ${id} rotating leader : ${old_leader} -> ${new_leader} ", + ("id", _id) + ("old_leader", current_leader) + ("new_leader", next_leader)); + + //leader changed, we send our new_view message + + reset_qc(NULL_PROPOSAL_ID); + + //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); + + _pending_proposal_block = NULL_BLOCK_ID; + + hs_new_view_message new_view; + + new_view.high_qc = _high_qc; + + send_hs_new_view_msg(new_view); + } + } + + //safenode predicate + bool qc_chain::is_node_safe(hs_proposal_message proposal){ + + //ilog(" === is_node_safe ==="); + + bool monotony_check = false; + bool safety_check = false; + bool liveness_check = false; + bool final_on_qc_check = false; + + fc::sha256 upcoming_commit; + + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated + else { + + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + if (chain_length>=2){ + + auto itr = current_qc_chain.begin(); + + hs_proposal_message b2 = *itr; + itr++; + hs_proposal_message b1 = *itr; + + if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; + else { + + proposal_store_type::nth_index<0>::type::iterator p_itr; + + p_itr = _proposal_store.get().find( b1.parent_id ); + + upcoming_commit = p_itr->final_on_qc; + } + } + + //abstracted [...] + if (upcoming_commit == proposal.final_on_qc){ + final_on_qc_check = true; + } + } + + if (proposal.get_height() > _v_height){ + monotony_check = true; + } + + if (_b_lock != NULL_PROPOSAL_ID){ + + //Safety check : check if this proposal extends the chain I'm locked on + if (extends(proposal.proposal_id, _b_lock)){ + safety_check = true; + } + + //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated + else { + proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); + proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); + + if (prop_justification->get_height() > b_lock->get_height()){ + liveness_check = true; + } + } + } + else { + //if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); + //if we're not locked on anything, means the protocol just activated or chain just launched + liveness_check = true; + safety_check = true; + } + +/* ilog(" === final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", + ("final_on_qc_check", final_on_qc_check) + ("monotony_check", monotony_check) + ("liveness_check", liveness_check) + ("safety_check", safety_check));*/ + + bool node_is_safe = final_on_qc_check && monotony_check && (liveness_check || safety_check); + if (!node_is_safe) { + + if (_errors) ilog(" *** node is NOT safe. Checks : final_on_qc: ${final_on_qc}, monotony_check: ${monotony_check}, liveness_check: ${liveness_check}, safety_check: ${safety_check})", + ("final_on_qc_check",final_on_qc_check) + ("monotony_check",monotony_check) + ("liveness_check",liveness_check) + ("safety_check",safety_check)); + } + + return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully + } + + //on proposal received, called from network thread + void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ + std::exception_ptr eptr; + try{ + //ilog(" === ${id} qc on_hs_proposal_msg ===", ("id", _id)); + //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + process_proposal(msg); + //ilog(" === end of on_hs_proposal_msg"); + } + catch (...){ + if (_errors) ilog(" *** ${id} error during on_hs_proposal_msg", ("id",_id)); + eptr = std::current_exception(); // capture + } + handle_eptr(eptr); + } + + //on vote received, called from network thread + void qc_chain::on_hs_vote_msg(hs_vote_message msg){ + std::exception_ptr eptr; + try{ + //ilog(" === ${id} qc on_hs_vote_msg ===", ("id", _id)); + //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + process_vote(msg); + //ilog(" === end of on_hs_vote_msg"); + } + catch (...){ + if (_errors) ilog(" *** ${id} error during on_hs_vote_msg", ("id",_id)); + eptr = std::current_exception(); // capture + } + handle_eptr(eptr); + } + + //on new view received, called from network thread + void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ + std::exception_ptr eptr; + try{ + //ilog(" === ${id} qc on_hs_new_view_msg ===", ("id", _id)); + //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + process_new_view(msg); + //ilog(" === end of on_hs_new_view_msg"); + } + catch (...){ + if (_errors) ilog(" *** ${id} error during on_hs_new_view_msg", ("id",_id)); + eptr = std::current_exception(); // capture + } + handle_eptr(eptr); + } + + //on new block received, called from network thread + void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ + std::exception_ptr eptr; + try{ + //ilog(" === ${id} qc on_hs_new_block_msg ===", ("id", _id)); + //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block + process_new_block(msg); + //ilog(" === end of on_hs_new_block_msg"); + } + catch (...){ + if (_errors) ilog(" *** ${id} error during on_hs_new_block_msg", ("id",_id)); + eptr = std::current_exception(); // capture + } + handle_eptr(eptr); + } + + void qc_chain::update(hs_proposal_message proposal){ + //ilog(" === update internal state ==="); + //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ + if (_log) ilog(" === ${id} proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)("id", _id)); + return; + } + + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + + size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); + + proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock); + + //ilog(" === update_high_qc : proposal.justify ==="); + update_high_qc(proposal.justify); + + if (chain_length<1){ + if (_log) ilog(" === ${id} qc chain length is 0", ("id", _id)); + return; + } + + auto itr = current_qc_chain.begin(); + hs_proposal_message b_2 = *itr; + + if (chain_length<2){ + if (_log) ilog(" === ${id} qc chain length is 1", ("id", _id)); + return; + } + + itr++; + + hs_proposal_message b_1 = *itr; + + //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock + +/* if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height} b_lock height ${b_lock_height}", + ("id", _id) + ("_b_lock", _b_lock) + ("b_1_height", b_1.block_num()) + ("b_1_phase", b_1.phase_counter) + ("b_lock_height", b_lock->block_num()) + ("b_lock_phase", b_lock->phase_counter));*/ + + if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ + //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); + _b_lock = b_1.proposal_id; //commit phase on b1 + //if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); + } + + if (chain_length<3){ + if (_log) ilog(" === ${id} qc chain length is 2",("id", _id)); + return; + } + + itr++; + + hs_proposal_message b = *itr; + +/* ilog(" === direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", + ("b_2.parent_id",b_2.parent_id) + ("b_1.proposal_id", b_1.proposal_id) + ("b_1.parent_id", b_1.parent_id) + ("b.proposal_id", b.proposal_id));*/ + + //direct parent relationship verification + if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ + + if (_b_exec!= NULL_PROPOSAL_ID){ + + proposal_store_type::nth_index<0>::type::iterator b_exec = _proposal_store.get().find( _b_exec); + + if (b_exec->get_height() >= b.get_height() && b_exec->proposal_id != b.proposal_id){ + + if (_errors) ilog(" *** ${id} finality violation detected at height ${block_num}, phase : ${phase}. Proposal ${proposal_id_1} conflicts with ${proposal_id_2}", + ("id", _id) + ("block_num", b.block_num()) + ("phase", b.phase_counter) + ("proposal_id_1", b.proposal_id) + ("proposal_id_2", b_exec->proposal_id)); + + _b_finality_violation = b.proposal_id; + + //protocol failure + return; + } + } + + commit(b); + + //ilog(" === last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); + + _b_exec = b.proposal_id; //decide phase on b + _block_exec = b.block_id; + + gc_proposals( b.get_height()-1); + } + else { + if (_errors) ilog(" *** ${id} could not verify direct parent relationship", ("id",_id)); + if (_errors) ilog(" *** b_2 ${b_2}", ("b_2", b_2)); + if (_errors) ilog(" *** b_1 ${b_1}", ("b_1", b_1)); + if (_errors) ilog(" *** b ${b}", ("b", b)); + } + } + + void qc_chain::gc_proposals(uint64_t cutoff){ + //ilog(" === garbage collection on old data"); + + auto end_itr = _proposal_store.get().upper_bound(cutoff); + while (_proposal_store.get().begin() != end_itr){ + + auto itr = _proposal_store.get().begin(); + +/* if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + ("id", _id) + ("block_num", itr->block_num()) + ("phase_counter", itr->phase_counter) + ("block_id", itr->block_id) + ("proposal_id", itr->proposal_id));*/ + + _proposal_store.get().erase(itr); + } + } + + void qc_chain::commit(hs_proposal_message proposal){ + +/* ilog(" === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", proposal.block_num()) + ("proposal_id", proposal.proposal_id) + ("block_id", proposal.block_id) + ("phase_counter", proposal.phase_counter) + ("parent_id", proposal.parent_id)); +*/ + bool exec_height_check = false; + + proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); + +/* ilog(" === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", last_exec_prop->block_num()) + ("proposal_id", last_exec_prop->proposal_id) + ("block_id", last_exec_prop->block_id) + ("phase_counter", last_exec_prop->phase_counter) + ("parent_id", last_exec_prop->parent_id));*/ + +/* ilog(" *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", + ("proposal_id_1", last_exec_prop->block_num()) + ("phase_counter_1", last_exec_prop->phase_counter) + ("proposal_id_2", proposal.block_num()) + ("phase_counter_2", proposal.phase_counter));*/ + + if (_b_exec==NULL_PROPOSAL_ID){ + exec_height_check = true; + } + else exec_height_check = last_exec_prop->get_height() < proposal.get_height(); + + if (exec_height_check){ + + proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); + + if (p_itr != _proposal_store.get().end()){ + //ilog(" === recursively committing" ); + commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first + } + + //Execute commands [...] + + if (_log) ilog(" === ${id} committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("block_id", proposal.block_id) + ("proposal_id", proposal.proposal_id)); + } + +/* else { + if (_errors) ilog(" *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id)); + }*/ + } + +}} diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 98262a6168..2a047a1d8b 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -1,845 +1,829 @@ -#define BOOST_TEST_MODULE hotstuff -#include - -#include - -#include - -#include - -#include - -#include -#include - -#include - -using namespace eosio::hotstuff; - -using std::cout; - -std::vector ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c39"), - block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530684"), - block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf330")}; - - -std::vector alternate_ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c31"), - block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530681"), - block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf331")}; - - -//list of unique replicas for our test -std::vector unique_replicas{ "bpa"_n, "bpb"_n, "bpc"_n, - "bpd"_n, "bpe"_n, "bpf"_n, - "bpg"_n, "bph"_n, "bpi"_n, - "bpj"_n, "bpk"_n, "bpl"_n, - "bpm"_n, "bpn"_n, "bpo"_n, - "bpp"_n, "bpq"_n, "bpr"_n, - "bps"_n, "bpt"_n, "bpu"_n }; - - - - - -class hotstuff_test_handler { -public: - - std::vector> _qc_chains; - - void initialize_qc_chains(test_pacemaker& tpm, std::vector info_loggers, std::vector error_loggers, std::vector replicas){ - - _qc_chains.clear(); - - for (name r : replicas){ - - _qc_chains.push_back(std::make_pair(r, qc_chain())); - - } - - int counter = 0; - - auto itr = _qc_chains.begin(); - - while (itr!=_qc_chains.end()){ - - bool log = false; - bool err = false; - - auto i_found = std::find(info_loggers.begin(), info_loggers.end(), replicas[counter]); - auto e_found = std::find(error_loggers.begin(), error_loggers.end(), replicas[counter]); - - if (i_found!=info_loggers.end()) log = true; - if (e_found!=error_loggers.end()) err = true; - - itr->second.init(replicas[counter], tpm, {replicas[counter]}, log, err); - - itr++; - counter++; - - } - - } - - void print_msgs(std::vector msgs ){ - - size_t proposals_count = 0; - size_t votes_count = 0; - size_t new_blocks_count = 0; - size_t new_views_count = 0; - - auto msg_itr = msgs.begin(); - - while (msg_itr!=msgs.end()){ - - size_t v_index = msg_itr->second.index(); - - if(v_index==0) proposals_count++; - if(v_index==1) votes_count++; - if(v_index==2) new_blocks_count++; - if(v_index==3) new_views_count++; - - msg_itr++; - - } - - std::cout << "\n"; - - std::cout << " message queue size : " << msgs.size() << "\n"; - std::cout << " proposals : " << proposals_count << "\n"; - std::cout << " votes : " << votes_count << "\n"; - std::cout << " new_blocks : " << new_blocks_count << "\n"; - std::cout << " new_views : " << new_views_count << "\n"; - - std::cout << "\n"; - - } - - void print_msg_queue(test_pacemaker &tpm){ - - print_msgs(tpm._pending_message_queue); - - } - - void print_pm_state(test_pacemaker &tpm){ - - std::cout << "\n"; - - std::cout << " leader : " << tpm.get_leader() << "\n"; - std::cout << " next leader : " << tpm.get_next_leader() << "\n"; - std::cout << " proposer : " << tpm.get_proposer() << "\n"; - std::cout << " current block id : " << tpm.get_current_block_id().str() << "\n"; - - std::cout << "\n"; - - } - - void print_bp_state(name bp, std::string message){ - - std::cout << "\n"; - std::cout << message; - std::cout << "\n"; - - auto qcc = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == bp; }); - - auto leaf_itr = qcc->second._proposal_store.get().find( qcc->second._b_leaf ); - auto qc_itr = qcc->second._proposal_store.get().find( qcc->second._high_qc.proposal_id ); - auto lock_itr = qcc->second._proposal_store.get().find( qcc->second._b_lock ); - auto exec_itr = qcc->second._proposal_store.get().find( qcc->second._b_exec ); - - if (leaf_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << qcc->second._b_leaf.str() << " block_num : " << leaf_itr->block_num() << ", phase : " << unsigned(leaf_itr->phase_counter) << "\n"; - else std::cout << " - No b_leaf value " << "\n"; - - if (qc_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current high_qc is : " << qcc->second._high_qc.proposal_id.str() << " block_num : " << qc_itr->block_num() << ", phase : " << unsigned(qc_itr->phase_counter) << "\n"; - else std::cout << " - No high_qc value " << "\n"; - - if (lock_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_lock is : " << qcc->second._b_lock.str() << " block_num : " << lock_itr->block_num() << ", phase : " << unsigned(lock_itr->phase_counter) << "\n"; - else std::cout << " - No b_lock value " << "\n"; - - if (exec_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_exec is : " << qcc->second._b_exec.str() << " block_num : " << exec_itr->block_num() << ", phase : " << unsigned(exec_itr->phase_counter) << "\n"; - else std::cout << " - No b_exec value " << "\n"; - - std::cout << "\n"; - - } - -}; - -BOOST_AUTO_TEST_SUITE(hotstuff) - -BOOST_AUTO_TEST_CASE(hotstuff_bitset) try { - - boost::dynamic_bitset b( 8, 0 ); - - uint32_t c = b.to_ulong(); - - b.flip(0); //least significant bit - b.flip(1); - b.flip(2); - b.flip(3); - b.flip(4); - b.flip(5); - b.flip(6); - b.flip(7); //most significant bit - - uint32_t d = b.to_ulong(); - - for (boost::dynamic_bitset<>::size_type i = 0; i < b.size(); ++i){ - b.flip(i); - } - - uint32_t e = b.to_ulong(); - - std::cout << "c : " << c << "\n"; - std::cout << "d : " << d << "\n"; - std::cout << "e : " << e << "\n"; - - -} FC_LOG_AND_RETHROW(); - - -BOOST_AUTO_TEST_CASE(hotstuff_1) try { - - //test optimistic responsiveness (3 confirmations per block) - - test_pacemaker tpm; - - hotstuff_test_handler ht; - - ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n}, unique_replicas); - - tpm.set_proposer("bpa"_n); - tpm.set_leader("bpa"_n); - tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); - - auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); - auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); - -ht.print_bp_state("bpa"_n, ""); - - tpm.set_current_block_id(ids[0]); //first block - - tpm.beat(); //produce first block and associated proposal - - tpm.dispatch(""); //send proposal to replicas (prepare on first block) - -ht.print_bp_state("bpa"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //send votes on proposal (prepareQC on first block) - - tpm.dispatch(""); //send proposal to replicas (precommit on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) - - tpm.dispatch(""); //send proposal to replicas (commit on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //propagating votes on new proposal (commitQC on first block) - - tpm.dispatch(""); //send proposal to replicas (decide on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - - tpm.dispatch(""); //propagating votes on new proposal (decide on first block) - - tpm.set_current_block_id(ids[1]); //second block - - tpm.beat(); //produce second block and associated proposal - - tpm.dispatch(""); //send proposal to replicas (prepare on second block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - - tpm.dispatch(""); //send votes on proposal (prepareQC on second block) - - tpm.dispatch(""); //send proposal to replicas (precommit on second block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - - tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) - - tpm.dispatch(""); //send proposal to replicas (commit on second block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - - tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) - - tpm.dispatch(""); //send proposal to replicas (decide on second block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - - tpm.dispatch(""); //send proposal to replicas (decide on second block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - - //check bpb as well - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - -} FC_LOG_AND_RETHROW(); - -BOOST_AUTO_TEST_CASE(hotstuff_2) try { - - //test slower network (1 confirmation per block) - - test_pacemaker tpm; - - hotstuff_test_handler ht; - - ht.initialize_qc_chains(tpm, {"bpa"_n}, {"bpa"_n}, unique_replicas); - - tpm.set_proposer("bpa"_n); - tpm.set_leader("bpa"_n); - tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); - - auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); - auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); - - tpm.set_current_block_id(ids[0]); //first block - - tpm.beat(); //produce first block and associated proposal - - tpm.dispatch(""); //send proposal to replicas (prepare on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //send votes on proposal (prepareQC on first block) - - tpm.dispatch(""); //send proposal to replicas (precommit on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.set_current_block_id(ids[1]); //second block - - tpm.beat(); //produce second block and associated proposal - - tpm.dispatch(""); //send proposal to replicas (prepare on second block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //send votes on proposal (prepareQC on second block) - - tpm.dispatch(""); //send proposal to replicas (precommit on second block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - - tpm.set_current_block_id(ids[2]); //second block - - tpm.beat(); //produce third block and associated proposal - - tpm.dispatch(""); //propagating votes on new proposal (prepare on third block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - - tpm.dispatch(""); //send votes on proposal (prepareQC on third block) - - tpm.dispatch(""); //propagating votes on new proposal (precommitQC on third block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - - //check bpb as well - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - -} FC_LOG_AND_RETHROW(); - -BOOST_AUTO_TEST_CASE(hotstuff_3) try { - - //test leader rotation - - test_pacemaker tpm; - - hotstuff_test_handler ht; - - ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n},unique_replicas); - - tpm.set_proposer("bpa"_n); - tpm.set_leader("bpa"_n); - tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); - - auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); - auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); - auto qcc_bpc = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpc"_n; }); - - tpm.set_current_block_id(ids[0]); //first block - - tpm.beat(); //produce first block and associated proposal - - tpm.dispatch(""); //send proposal to replicas (prepare on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //send votes on proposal (prepareQC on first block) - - tpm.dispatch(""); //send proposal to replicas (precommit on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) - - tpm.dispatch(""); //send proposal to replicas (commit on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.set_next_leader("bpb"_n); //leader is set to rotate on next block - - tpm.dispatch(""); //propagating votes on new proposal (commitQC on first block) - - tpm.dispatch(""); //send proposal to replicas (decide on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - - tpm.dispatch(""); //propagating votes on new proposal (decide on first block) - - tpm.set_proposer("bpb"_n); //leader has rotated - tpm.set_leader("bpb"_n); - - tpm.set_current_block_id(ids[1]); //second block - - tpm.beat(); //produce second block and associated proposal - - tpm.dispatch(""); //send proposal to replicas (prepare on second block) - - BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - - tpm.dispatch(""); //send votes on proposal (prepareQC on second block) - - tpm.dispatch(""); //send proposal to replicas (precommit on second block) - - BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - - tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) - - tpm.dispatch(""); //send proposal to replicas (commit on second block) - - BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - - tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) - - tpm.dispatch(""); //send proposal to replicas (decide on second block) - - BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - - //check bpa as well - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - - //check bpc as well - BOOST_CHECK_EQUAL(qcc_bpc->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpc->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpc->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - -} FC_LOG_AND_RETHROW(); - -BOOST_AUTO_TEST_CASE(hotstuff_4) try { - - //test loss and recovery of liveness on new block - - test_pacemaker tpm; - - hotstuff_test_handler ht; - - ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n}, unique_replicas); - - tpm.set_proposer("bpa"_n); - tpm.set_leader("bpa"_n); - tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); - - auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); - auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); - auto qcc_bpi = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpi"_n; }); - - tpm.set_current_block_id(ids[0]); //first block - - tpm.beat(); //produce first block and associated proposal - - tpm.dispatch(""); //send proposal to replicas (prepare on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //send votes on proposal (prepareQC on first block) - - tpm.dispatch(""); //send proposal to replicas (precommit on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) - -//ht.print_bp_state("bpa"_n, "before deactivate"); - - tpm.deactivate("bpb"_n); //loss of liveness as 7 finalizers out of 21 go offline - tpm.deactivate("bpc"_n); - tpm.deactivate("bpd"_n); - tpm.deactivate("bpe"_n); - tpm.deactivate("bpf"_n); - tpm.deactivate("bpg"_n); - tpm.deactivate("bph"_n); - - tpm.dispatch(""); //send proposal to replicas (commit on first block) - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.set_next_leader("bpi"_n); //leader is set to rotate on next block - - tpm.dispatch(""); //propagating votes on new proposal (insufficient to reach quorum) - -//ht.print_bp_state("bpa"_n, "before reactivate"); - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.activate("bpb"_n); - tpm.activate("bpc"_n); - tpm.activate("bpd"_n); - tpm.activate("bpe"_n); - tpm.activate("bpf"_n); - tpm.activate("bpg"_n); - tpm.activate("bph"_n); - - tpm.set_proposer("bpi"_n); - tpm.set_leader("bpi"_n); - - tpm.set_current_block_id(ids[1]); //second block - - tpm.beat(); //produce second block and associated proposal - - tpm.dispatch(""); //send proposal to replicas (prepare on second block) - -//ht.print_bp_state("bpi"_n, ""); - -//ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm.dispatch(""); //send votes on proposal (prepareQC on second block) - - tpm.dispatch(""); //send proposal to replicas (precommit on second block) - -//ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - - tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) - - tpm.dispatch(""); //send proposal to replicas (commit on second block) - -//ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - - tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) - - tpm.dispatch(""); //send proposal to replicas (decide on second block) - -//ht.print_bp_state("bpa"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - -//ht.print_bp_state("bpb"_n, ""); - //check bpa as well - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - -//ht.print_bp_state("bpi"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpi->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpi->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpi->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - - BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - -} FC_LOG_AND_RETHROW(); - -BOOST_AUTO_TEST_CASE(hotstuff_5) try { - - //test finality violation - - std::vector honest_replica_set_1 { "bpb"_n, - "bpe"_n, - "bph"_n, - "bpk"_n, - "bpn"_n, - "bpq"_n }; - - std::vector honest_replica_set_2 { "bpa"_n, - "bpd"_n, - "bpg"_n, - "bpj"_n, - "bpm"_n, - "bpp"_n }; - - std::vector byzantine_set { "bpc"_n, - "bpf"_n, - "bpi"_n, - "bpl"_n, - "bpo"_n, - "bpr"_n, - "bpu"_n, - "bps"_n, - "bpt"_n }; - - std::vector replica_set_1; - std::vector replica_set_2; - - replica_set_1.reserve( honest_replica_set_1.size() + byzantine_set.size() ); - replica_set_2.reserve( honest_replica_set_2.size() + byzantine_set.size() ); - - replica_set_1.insert( replica_set_1.end(), honest_replica_set_1.begin(), honest_replica_set_1.end() ); - replica_set_1.insert( replica_set_1.end(), byzantine_set.begin(), byzantine_set.end() ); - - replica_set_2.insert( replica_set_2.end(), honest_replica_set_2.begin(), honest_replica_set_2.end() ); - replica_set_2.insert( replica_set_2.end(), byzantine_set.begin(), byzantine_set.end() ); - - //simulating a fork, where - test_pacemaker tpm1; - test_pacemaker tpm2; - - hotstuff_test_handler ht1; - hotstuff_test_handler ht2; - - ht1.initialize_qc_chains(tpm1, {"bpe"_n}, {"bpe"_n}, replica_set_1); - - ht2.initialize_qc_chains(tpm2, {}, {}, replica_set_2); - - tpm1.set_proposer("bpe"_n); //honest leader - tpm1.set_leader("bpe"_n); - tpm1.set_next_leader("bpe"_n); - tpm1.set_finalizers(replica_set_1); - - tpm2.set_proposer("bpf"_n); //byzantine leader - tpm2.set_leader("bpf"_n); - tpm2.set_next_leader("bpf"_n); - tpm2.set_finalizers(replica_set_2); - - auto qcc_bpe = std::find_if(ht1._qc_chains.begin(), ht1._qc_chains.end(), [&](const auto& q){ return q.first == "bpe"_n; }); - //auto qcc_bpf = std::find_if(ht2._qc_chains.begin(), ht2._qc_chains.end(), [&](const auto& q){ return q.first == "bpf"_n; }); - - std::vector msgs; - - tpm1.set_current_block_id(ids[0]); //first block - tpm2.set_current_block_id(ids[0]); //first block - - tpm1.beat(); //produce first block and associated proposal - tpm2.beat(); //produce first block and associated proposal - - tpm1.dispatch(""); - tpm1.dispatch(""); - - tpm2.dispatch(""); - tpm2.dispatch(""); - -//ht1.print_bp_state("bpe"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm1.dispatch(""); - tpm1.dispatch(""); - - tpm2.dispatch(""); - tpm2.dispatch(""); - -//ht1.print_bp_state("bpe"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - - tpm1.dispatch(""); - tpm1.dispatch(""); - - tpm2.dispatch(""); - tpm2.dispatch(""); - -//ht1.print_bp_state("bpe"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - - tpm1.dispatch(""); - tpm1.dispatch(""); - - tpm2.dispatch(""); - tpm2.dispatch(""); - -//ht1.print_bp_state("bpe"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - - tpm1.set_current_block_id(ids[1]); //first block - tpm2.set_current_block_id(alternate_ids[1]); //first block - - tpm1.beat(); //produce second block and associated proposal - tpm2.beat(); //produce second block and associated proposal - - tpm1.pipe(tpm2.dispatch("")); - tpm1.dispatch(""); - - tpm1.pipe(tpm2.dispatch("")); - tpm1.dispatch(""); - -//ht1.print_bp_state("bpe"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - - tpm1.pipe(tpm2.dispatch("")); - tpm1.dispatch(""); - - tpm1.pipe(tpm2.dispatch("")); - tpm1.dispatch(""); - -//ht1.print_bp_state("bpe"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - - tpm1.pipe(tpm2.dispatch("")); - tpm1.dispatch(""); - - tpm1.pipe(tpm2.dispatch("")); - tpm1.dispatch(""); - -//ht1.print_bp_state("bpe"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - - tpm1.pipe(tpm2.dispatch("")); - tpm1.dispatch(""); - - tpm1.pipe(tpm2.dispatch("")); - tpm1.dispatch(""); - -//ht1.print_bp_state("bpe"_n, ""); - - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - - BOOST_CHECK_EQUAL(qcc_bpe->second._b_finality_violation.str(), std::string("5585accc44c753636d1381067c7f915d7fff2d33846aae04820abc055d952860")); - -} FC_LOG_AND_RETHROW(); - -BOOST_AUTO_TEST_SUITE_END() +#define BOOST_TEST_MODULE hotstuff + +#include + +#include +#include +#include + +#include + +#include +#include + +#include + +using namespace eosio::hotstuff; + +using std::cout; + +std::vector ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c39"), + block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530684"), + block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf330")}; + +std::vector alternate_ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c31"), + block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530681"), + block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf331")}; + +//list of unique replicas for our test +std::vector unique_replicas{ + "bpa"_n, "bpb"_n, "bpc"_n, + "bpd"_n, "bpe"_n, "bpf"_n, + "bpg"_n, "bph"_n, "bpi"_n, + "bpj"_n, "bpk"_n, "bpl"_n, + "bpm"_n, "bpn"_n, "bpo"_n, + "bpp"_n, "bpq"_n, "bpr"_n, + "bps"_n, "bpt"_n, "bpu"_n }; + +class hotstuff_test_handler { +public: + + std::vector> _qc_chains; + + void initialize_qc_chains(test_pacemaker& tpm, std::vector info_loggers, std::vector error_loggers, std::vector replicas){ + + _qc_chains.clear(); + + for (name r : replicas){ + + _qc_chains.push_back(std::make_pair(r, qc_chain())); + + } + + int counter = 0; + + auto itr = _qc_chains.begin(); + + while (itr!=_qc_chains.end()){ + + bool log = false; + bool err = false; + + auto i_found = std::find(info_loggers.begin(), info_loggers.end(), replicas[counter]); + auto e_found = std::find(error_loggers.begin(), error_loggers.end(), replicas[counter]); + + if (i_found!=info_loggers.end()) log = true; + if (e_found!=error_loggers.end()) err = true; + + itr->second.init(replicas[counter], tpm, {replicas[counter]}, log, err); + + itr++; + counter++; + } + } + + void print_msgs(std::vector msgs ){ + + size_t proposals_count = 0; + size_t votes_count = 0; + size_t new_blocks_count = 0; + size_t new_views_count = 0; + + auto msg_itr = msgs.begin(); + + while (msg_itr!=msgs.end()){ + + size_t v_index = msg_itr->second.index(); + + if(v_index==0) proposals_count++; + if(v_index==1) votes_count++; + if(v_index==2) new_blocks_count++; + if(v_index==3) new_views_count++; + + msg_itr++; + } + + std::cout << "\n"; + + std::cout << " message queue size : " << msgs.size() << "\n"; + std::cout << " proposals : " << proposals_count << "\n"; + std::cout << " votes : " << votes_count << "\n"; + std::cout << " new_blocks : " << new_blocks_count << "\n"; + std::cout << " new_views : " << new_views_count << "\n"; + + std::cout << "\n"; + } + + void print_msg_queue(test_pacemaker &tpm){ + print_msgs(tpm._pending_message_queue); + } + + void print_pm_state(test_pacemaker &tpm){ + std::cout << "\n"; + std::cout << " leader : " << tpm.get_leader() << "\n"; + std::cout << " next leader : " << tpm.get_next_leader() << "\n"; + std::cout << " proposer : " << tpm.get_proposer() << "\n"; + std::cout << " current block id : " << tpm.get_current_block_id().str() << "\n"; + std::cout << "\n"; + } + + void print_bp_state(name bp, std::string message){ + + std::cout << "\n"; + std::cout << message; + std::cout << "\n"; + + auto qcc = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == bp; }); + + auto leaf_itr = qcc->second._proposal_store.get().find( qcc->second._b_leaf ); + auto qc_itr = qcc->second._proposal_store.get().find( qcc->second._high_qc.proposal_id ); + auto lock_itr = qcc->second._proposal_store.get().find( qcc->second._b_lock ); + auto exec_itr = qcc->second._proposal_store.get().find( qcc->second._b_exec ); + + if (leaf_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << qcc->second._b_leaf.str() << " block_num : " << leaf_itr->block_num() << ", phase : " << unsigned(leaf_itr->phase_counter) << "\n"; + else std::cout << " - No b_leaf value " << "\n"; + + if (qc_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current high_qc is : " << qcc->second._high_qc.proposal_id.str() << " block_num : " << qc_itr->block_num() << ", phase : " << unsigned(qc_itr->phase_counter) << "\n"; + else std::cout << " - No high_qc value " << "\n"; + + if (lock_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_lock is : " << qcc->second._b_lock.str() << " block_num : " << lock_itr->block_num() << ", phase : " << unsigned(lock_itr->phase_counter) << "\n"; + else std::cout << " - No b_lock value " << "\n"; + + if (exec_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_exec is : " << qcc->second._b_exec.str() << " block_num : " << exec_itr->block_num() << ", phase : " << unsigned(exec_itr->phase_counter) << "\n"; + else std::cout << " - No b_exec value " << "\n"; + + std::cout << "\n"; + } +}; + +BOOST_AUTO_TEST_SUITE(hotstuff) + +BOOST_AUTO_TEST_CASE(hotstuff_bitset) try { + + boost::dynamic_bitset b( 8, 0 ); + + uint32_t c = b.to_ulong(); + + b.flip(0); //least significant bit + b.flip(1); + b.flip(2); + b.flip(3); + b.flip(4); + b.flip(5); + b.flip(6); + b.flip(7); //most significant bit + + uint32_t d = b.to_ulong(); + + for (boost::dynamic_bitset<>::size_type i = 0; i < b.size(); ++i){ + b.flip(i); + } + + uint32_t e = b.to_ulong(); + + std::cout << "c : " << c << "\n"; + std::cout << "d : " << d << "\n"; + std::cout << "e : " << e << "\n"; + +} FC_LOG_AND_RETHROW(); + + +BOOST_AUTO_TEST_CASE(hotstuff_1) try { + + //test optimistic responsiveness (3 confirmations per block) + + test_pacemaker tpm; + + hotstuff_test_handler ht; + + ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n}, unique_replicas); + + tpm.set_proposer("bpa"_n); + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); + + auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + + ht.print_bp_state("bpa"_n, ""); + + tpm.set_current_block_id(ids[0]); //first block + + tpm.beat(); //produce first block and associated proposal + + tpm.dispatch(""); //send proposal to replicas (prepare on first block) + + ht.print_bp_state("bpa"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on first block) + + tpm.dispatch(""); //send proposal to replicas (precommit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) + + tpm.dispatch(""); //send proposal to replicas (commit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //propagating votes on new proposal (commitQC on first block) + + tpm.dispatch(""); //send proposal to replicas (decide on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.dispatch(""); //propagating votes on new proposal (decide on first block) + + tpm.set_current_block_id(ids[1]); //second block + + tpm.beat(); //produce second block and associated proposal + + tpm.dispatch(""); //send proposal to replicas (prepare on second block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on second block) + + tpm.dispatch(""); //send proposal to replicas (precommit on second block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) + + tpm.dispatch(""); //send proposal to replicas (commit on second block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + + tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) + + tpm.dispatch(""); //send proposal to replicas (decide on second block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + + tpm.dispatch(""); //send proposal to replicas (decide on second block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + + //check bpb as well + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_2) try { + + //test slower network (1 confirmation per block) + + test_pacemaker tpm; + + hotstuff_test_handler ht; + + ht.initialize_qc_chains(tpm, {"bpa"_n}, {"bpa"_n}, unique_replicas); + + tpm.set_proposer("bpa"_n); + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); + + auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + + tpm.set_current_block_id(ids[0]); //first block + + tpm.beat(); //produce first block and associated proposal + + tpm.dispatch(""); //send proposal to replicas (prepare on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on first block) + + tpm.dispatch(""); //send proposal to replicas (precommit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.set_current_block_id(ids[1]); //second block + + tpm.beat(); //produce second block and associated proposal + + tpm.dispatch(""); //send proposal to replicas (prepare on second block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on second block) + + tpm.dispatch(""); //send proposal to replicas (precommit on second block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.set_current_block_id(ids[2]); //second block + + tpm.beat(); //produce third block and associated proposal + + tpm.dispatch(""); //propagating votes on new proposal (prepare on third block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on third block) + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on third block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + + //check bpb as well + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_3) try { + + //test leader rotation + + test_pacemaker tpm; + + hotstuff_test_handler ht; + + ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n},unique_replicas); + + tpm.set_proposer("bpa"_n); + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); + + auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + auto qcc_bpc = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpc"_n; }); + + tpm.set_current_block_id(ids[0]); //first block + + tpm.beat(); //produce first block and associated proposal + + tpm.dispatch(""); //send proposal to replicas (prepare on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on first block) + + tpm.dispatch(""); //send proposal to replicas (precommit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) + + tpm.dispatch(""); //send proposal to replicas (commit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.set_next_leader("bpb"_n); //leader is set to rotate on next block + + tpm.dispatch(""); //propagating votes on new proposal (commitQC on first block) + + tpm.dispatch(""); //send proposal to replicas (decide on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.dispatch(""); //propagating votes on new proposal (decide on first block) + + tpm.set_proposer("bpb"_n); //leader has rotated + tpm.set_leader("bpb"_n); + + tpm.set_current_block_id(ids[1]); //second block + + tpm.beat(); //produce second block and associated proposal + + tpm.dispatch(""); //send proposal to replicas (prepare on second block) + + BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on second block) + + tpm.dispatch(""); //send proposal to replicas (precommit on second block) + + BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) + + tpm.dispatch(""); //send proposal to replicas (commit on second block) + + BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + + tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) + + tpm.dispatch(""); //send proposal to replicas (decide on second block) + + BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + + //check bpa as well + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + + //check bpc as well + BOOST_CHECK_EQUAL(qcc_bpc->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpc->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpc->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_4) try { + + //test loss and recovery of liveness on new block + + test_pacemaker tpm; + + hotstuff_test_handler ht; + + ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n}, unique_replicas); + + tpm.set_proposer("bpa"_n); + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); + + auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + auto qcc_bpi = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpi"_n; }); + + tpm.set_current_block_id(ids[0]); //first block + + tpm.beat(); //produce first block and associated proposal + + tpm.dispatch(""); //send proposal to replicas (prepare on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on first block) + + tpm.dispatch(""); //send proposal to replicas (precommit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) + +//ht.print_bp_state("bpa"_n, "before deactivate"); + + tpm.deactivate("bpb"_n); //loss of liveness as 7 finalizers out of 21 go offline + tpm.deactivate("bpc"_n); + tpm.deactivate("bpd"_n); + tpm.deactivate("bpe"_n); + tpm.deactivate("bpf"_n); + tpm.deactivate("bpg"_n); + tpm.deactivate("bph"_n); + + tpm.dispatch(""); //send proposal to replicas (commit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.set_next_leader("bpi"_n); //leader is set to rotate on next block + + tpm.dispatch(""); //propagating votes on new proposal (insufficient to reach quorum) + +//ht.print_bp_state("bpa"_n, "before reactivate"); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.activate("bpb"_n); + tpm.activate("bpc"_n); + tpm.activate("bpd"_n); + tpm.activate("bpe"_n); + tpm.activate("bpf"_n); + tpm.activate("bpg"_n); + tpm.activate("bph"_n); + + tpm.set_proposer("bpi"_n); + tpm.set_leader("bpi"_n); + + tpm.set_current_block_id(ids[1]); //second block + + tpm.beat(); //produce second block and associated proposal + + tpm.dispatch(""); //send proposal to replicas (prepare on second block) + +//ht.print_bp_state("bpi"_n, ""); + +//ht.print_bp_state("bpa"_n, ""); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on second block) + + tpm.dispatch(""); //send proposal to replicas (precommit on second block) + +//ht.print_bp_state("bpa"_n, ""); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) + + tpm.dispatch(""); //send proposal to replicas (commit on second block) + +//ht.print_bp_state("bpa"_n, ""); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + + tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) + + tpm.dispatch(""); //send proposal to replicas (decide on second block) + +//ht.print_bp_state("bpa"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + +//ht.print_bp_state("bpb"_n, ""); + //check bpa as well + BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + +//ht.print_bp_state("bpi"_n, ""); + BOOST_CHECK_EQUAL(qcc_bpi->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpi->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpi->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + + BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(hotstuff_5) try { + + //test finality violation + + std::vector honest_replica_set_1 { + "bpb"_n, + "bpe"_n, + "bph"_n, + "bpk"_n, + "bpn"_n, + "bpq"_n }; + + std::vector honest_replica_set_2 { + "bpa"_n, + "bpd"_n, + "bpg"_n, + "bpj"_n, + "bpm"_n, + "bpp"_n }; + + std::vector byzantine_set { + "bpc"_n, + "bpf"_n, + "bpi"_n, + "bpl"_n, + "bpo"_n, + "bpr"_n, + "bpu"_n, + "bps"_n, + "bpt"_n }; + + std::vector replica_set_1; + std::vector replica_set_2; + + replica_set_1.reserve( honest_replica_set_1.size() + byzantine_set.size() ); + replica_set_2.reserve( honest_replica_set_2.size() + byzantine_set.size() ); + + replica_set_1.insert( replica_set_1.end(), honest_replica_set_1.begin(), honest_replica_set_1.end() ); + replica_set_1.insert( replica_set_1.end(), byzantine_set.begin(), byzantine_set.end() ); + + replica_set_2.insert( replica_set_2.end(), honest_replica_set_2.begin(), honest_replica_set_2.end() ); + replica_set_2.insert( replica_set_2.end(), byzantine_set.begin(), byzantine_set.end() ); + + //simulating a fork, where + test_pacemaker tpm1; + test_pacemaker tpm2; + + hotstuff_test_handler ht1; + hotstuff_test_handler ht2; + + ht1.initialize_qc_chains(tpm1, {"bpe"_n}, {"bpe"_n}, replica_set_1); + + ht2.initialize_qc_chains(tpm2, {}, {}, replica_set_2); + + tpm1.set_proposer("bpe"_n); //honest leader + tpm1.set_leader("bpe"_n); + tpm1.set_next_leader("bpe"_n); + tpm1.set_finalizers(replica_set_1); + + tpm2.set_proposer("bpf"_n); //byzantine leader + tpm2.set_leader("bpf"_n); + tpm2.set_next_leader("bpf"_n); + tpm2.set_finalizers(replica_set_2); + + auto qcc_bpe = std::find_if(ht1._qc_chains.begin(), ht1._qc_chains.end(), [&](const auto& q){ return q.first == "bpe"_n; }); + //auto qcc_bpf = std::find_if(ht2._qc_chains.begin(), ht2._qc_chains.end(), [&](const auto& q){ return q.first == "bpf"_n; }); + + std::vector msgs; + + tpm1.set_current_block_id(ids[0]); //first block + tpm2.set_current_block_id(ids[0]); //first block + + tpm1.beat(); //produce first block and associated proposal + tpm2.beat(); //produce first block and associated proposal + + tpm1.dispatch(""); + tpm1.dispatch(""); + + tpm2.dispatch(""); + tpm2.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm1.dispatch(""); + tpm1.dispatch(""); + + tpm2.dispatch(""); + tpm2.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm1.dispatch(""); + tpm1.dispatch(""); + + tpm2.dispatch(""); + tpm2.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm1.dispatch(""); + tpm1.dispatch(""); + + tpm2.dispatch(""); + tpm2.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm1.set_current_block_id(ids[1]); //first block + tpm2.set_current_block_id(alternate_ids[1]); //first block + + tpm1.beat(); //produce second block and associated proposal + tpm2.beat(); //produce second block and associated proposal + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + + tpm1.pipe(tpm2.dispatch("")); + tpm1.dispatch(""); + +//ht1.print_bp_state("bpe"_n, ""); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + + BOOST_CHECK_EQUAL(qcc_bpe->second._b_finality_violation.str(), std::string("5585accc44c753636d1381067c7f915d7fff2d33846aae04820abc055d952860")); + +} FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_SUITE_END() diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test_pacemaker.cpp index 075c888920..c7789b4063 100644 --- a/libraries/hotstuff/test_pacemaker.cpp +++ b/libraries/hotstuff/test_pacemaker.cpp @@ -1,339 +1,279 @@ -#include -#include - -namespace eosio { namespace hotstuff { - - void test_pacemaker::set_proposer(name proposer){ - _proposer = proposer; - }; - - void test_pacemaker::set_leader(name leader){ - _leader = leader; - }; - - void test_pacemaker::set_next_leader(name next_leader){ - _next_leader = next_leader; - }; - - void test_pacemaker::set_finalizers(std::vector finalizers){ - _finalizers = finalizers; - }; - - void test_pacemaker::set_current_block_id(block_id_type id){ - _current_block_id = id; - }; - - void test_pacemaker::set_quorum_threshold(uint32_t threshold){ - _quorum_threshold = threshold; - } - - void test_pacemaker::add_message_to_queue(hotstuff_message msg){ - _pending_message_queue.push_back(msg); - } - - void test_pacemaker::pipe(std::vector messages){ - - auto itr = messages.begin(); - - while (itr != messages.end()){ - - _pending_message_queue.push_back(*itr); - - itr++; - } - - } - - std::vector test_pacemaker::dispatch(std::string memo, int count){ - - for (int i = 0 ; i < count ; i++){ - this->dispatch(memo); - } - } - - std::vector test_pacemaker::dispatch(std::string memo){ - - int count = 1; - - //ilog(" === propagate ${count} messages", ("count", _pending_message_queue.size())); - - std::vector dispatched_messages = _pending_message_queue; - _message_queue = _pending_message_queue; - - while (_pending_message_queue.begin()!=_pending_message_queue.end()){ - - auto itr = _pending_message_queue.end(); - itr--; - - _pending_message_queue.erase(itr); - - } - - //ilog(" === propagate ${count} messages", ("count", _message_queue.size())); - - size_t proposals_count = 0; - size_t votes_count = 0; - size_t new_blocks_count = 0; - size_t new_views_count = 0; - - auto msg_itr = _message_queue.begin(); - - while (msg_itr!=_message_queue.end()){ - - size_t v_index = msg_itr->second.index(); - - if(v_index==0) proposals_count++; - if(v_index==1) votes_count++; - if(v_index==2) new_blocks_count++; - if(v_index==3) new_views_count++; - - //ilog(" === propagating message ${count} : type : ${index}", ("count", count) ("index", msg_itr->index())); - - if (msg_itr->second.index() == 0) on_hs_proposal_msg(msg_itr->first, std::get(msg_itr->second)); - else if (msg_itr->second.index() == 1) on_hs_vote_msg(msg_itr->first, std::get(msg_itr->second)); - else if (msg_itr->second.index() == 2) on_hs_new_block_msg(msg_itr->first, std::get(msg_itr->second)); - else if (msg_itr->second.index() == 3) on_hs_new_view_msg(msg_itr->first, std::get(msg_itr->second)); - - - msg_itr++; - - //ilog(" === after erase"); - - count++; - - } - - //ilog(" === erase"); - - while (_message_queue.begin()!=_message_queue.end()){ - - auto itr = _message_queue.end(); - itr--; - - _message_queue.erase(itr); - - } - - //ilog(" === after erase"); - - if (memo!=""){ - ilog(" === ${memo} : ", - ("memo", memo)); - } - - ilog(" === pacemaker dispatched ${proposals} proposals, ${votes} votes, ${new_blocks} new_blocks, ${new_views} new_views", - ("proposals", proposals_count) - ("votes", votes_count) - ("new_blocks", new_blocks_count) - ("new_views", new_views_count)); - - return dispatched_messages; - - } - - void test_pacemaker::activate(name replica){ - - auto qc_itr = _qcc_store.get().find( replica.to_uint64_t() ); - - if (qc_itr==_qcc_store.end()) throw std::runtime_error("replica not found"); - - _qcc_store.modify(qc_itr, [&]( auto& qcc ){ - qcc._active = true; - }); - } - - void test_pacemaker::deactivate(name replica){ - - auto qc_itr = _qcc_store.get().find( replica.to_uint64_t() ); - - if (qc_itr==_qcc_store.end()) throw std::runtime_error("replica not found"); - - _qcc_store.modify(qc_itr, [&]( auto& qcc ){ - qcc._active = false; - }); - - } - - name test_pacemaker::get_proposer(){ - return _proposer; - }; - - name test_pacemaker::get_leader(){ - return _leader; - }; - - name test_pacemaker::get_next_leader(){ - return _next_leader; - }; - - std::vector test_pacemaker::get_finalizers(){ - return _finalizers; - }; - - block_id_type test_pacemaker::get_current_block_id(){ - return _current_block_id; - }; - - uint32_t test_pacemaker::get_quorum_threshold(){ - return _quorum_threshold; - }; - - void test_pacemaker::beat(){ - - auto itr = _qcc_store.get().find( _proposer.to_uint64_t() ); - - if (itr==_qcc_store.end()) throw std::runtime_error("proposer not found"); - - itr->_qc_chain->on_beat(); - - }; - - void test_pacemaker::assign_qc_chain(name name, qc_chain& qcc){ - - //ilog("reg listener"); - - auto itr = _qcc_store.get().find( name.to_uint64_t() ); - - //ilog("got itr"); - - if (itr!=_qcc_store.end()){ - - throw std::runtime_error("duplicate qc chain"); - - } - else { - - //ilog("new listener ${name}", ("name", name)); - - //_unique_replicas.push_back(name); - - indexed_qc_chain iqcc; - - iqcc._name = name; - iqcc._active = true; - iqcc._qc_chain = &qcc; - - //ilog(" === register_listener 1 ${my_producers}", ("my_producers", iqcc._qc_chain->_my_producers)); - - _qcc_store.insert(iqcc); - - //auto itr = _qcc_store.get().find( name.to_uint64_t() ); - - //ilog(" === register_listener 2 ${my_producers}", ("my_producers", itr->_qc_chain->_my_producers)); - - - } - - - }; - - void test_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ - - //ilog("queuing hs_proposal_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); - - _pending_message_queue.push_back(std::make_pair(id, msg)); - - }; - - void test_pacemaker::send_hs_vote_msg(name id, hs_vote_message msg){ - - //ilog("queuing hs_vote_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); - - _pending_message_queue.push_back(std::make_pair(id, msg)); - - }; - - void test_pacemaker::send_hs_new_block_msg(name id, hs_new_block_message msg){ - - _pending_message_queue.push_back(std::make_pair(id, msg)); - - }; - - void test_pacemaker::send_hs_new_view_msg(name id, hs_new_view_message msg){ - - _pending_message_queue.push_back(std::make_pair(id, msg)); - - }; - - void test_pacemaker::on_hs_proposal_msg(name id, hs_proposal_message msg){ - - //ilog(" === on_hs_proposal_msg"); - auto qc_itr = _qcc_store.begin(); - - while (qc_itr!=_qcc_store.end()){ - - //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - - if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); - - if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_proposal_msg(msg); - - qc_itr++; - - } - - //ilog(" === end on_hs_proposal_msg"); - - } - - void test_pacemaker::on_hs_vote_msg(name id, hs_vote_message msg){ - - //ilog(" === on_hs_vote_msg"); - auto qc_itr = _qcc_store.begin(); - - while (qc_itr!=_qcc_store.end()){ - - //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - - if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); - - if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_vote_msg(msg); - - qc_itr++; - } - - //ilog(" === end on_hs_vote_msg"); - - } - - void test_pacemaker::on_hs_new_block_msg(name id, hs_new_block_message msg){ - - //ilog(" === on_hs_new_block_msg"); - auto qc_itr = _qcc_store.begin(); - - while (qc_itr!=_qcc_store.end()){ - - //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - - if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); - - if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_block_msg(msg); - - qc_itr++; - } - - //ilog(" === end on_hs_new_block_msg"); - - } - - void test_pacemaker::on_hs_new_view_msg(name id, hs_new_view_message msg){ - - //ilog(" === on_hs_new_view_msg"); - auto qc_itr = _qcc_store.begin(); - - while (qc_itr!=_qcc_store.end()){ - - //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - - if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); - - if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_view_msg(msg); - - qc_itr++; - } - - //ilog(" === end on_hs_new_view_msg"); - - } - -}} \ No newline at end of file +#include +#include + +namespace eosio { namespace hotstuff { + + void test_pacemaker::set_proposer(name proposer){ + _proposer = proposer; + }; + + void test_pacemaker::set_leader(name leader){ + _leader = leader; + }; + + void test_pacemaker::set_next_leader(name next_leader){ + _next_leader = next_leader; + }; + + void test_pacemaker::set_finalizers(std::vector finalizers){ + _finalizers = finalizers; + }; + + void test_pacemaker::set_current_block_id(block_id_type id){ + _current_block_id = id; + }; + + void test_pacemaker::set_quorum_threshold(uint32_t threshold){ + _quorum_threshold = threshold; + } + + void test_pacemaker::add_message_to_queue(hotstuff_message msg){ + _pending_message_queue.push_back(msg); + } + + void test_pacemaker::pipe(std::vector messages){ + auto itr = messages.begin(); + while (itr != messages.end()){ + _pending_message_queue.push_back(*itr); + itr++; + } + } + + std::vector test_pacemaker::dispatch(std::string memo, int count){ + for (int i = 0 ; i < count ; i++){ + this->dispatch(memo); + } + } + + std::vector test_pacemaker::dispatch(std::string memo){ + + int count = 1; + + //ilog(" === propagate ${count} messages", ("count", _pending_message_queue.size())); + + std::vector dispatched_messages = _pending_message_queue; + _message_queue = _pending_message_queue; + + while (_pending_message_queue.begin()!=_pending_message_queue.end()){ + + auto itr = _pending_message_queue.end(); + itr--; + + _pending_message_queue.erase(itr); + } + + //ilog(" === propagate ${count} messages", ("count", _message_queue.size())); + + size_t proposals_count = 0; + size_t votes_count = 0; + size_t new_blocks_count = 0; + size_t new_views_count = 0; + + auto msg_itr = _message_queue.begin(); + + while (msg_itr!=_message_queue.end()){ + + size_t v_index = msg_itr->second.index(); + + if(v_index==0) proposals_count++; + if(v_index==1) votes_count++; + if(v_index==2) new_blocks_count++; + if(v_index==3) new_views_count++; + + //ilog(" === propagating message ${count} : type : ${index}", ("count", count) ("index", msg_itr->index())); + + if (msg_itr->second.index() == 0) on_hs_proposal_msg(msg_itr->first, std::get(msg_itr->second)); + else if (msg_itr->second.index() == 1) on_hs_vote_msg(msg_itr->first, std::get(msg_itr->second)); + else if (msg_itr->second.index() == 2) on_hs_new_block_msg(msg_itr->first, std::get(msg_itr->second)); + else if (msg_itr->second.index() == 3) on_hs_new_view_msg(msg_itr->first, std::get(msg_itr->second)); + + msg_itr++; + + //ilog(" === after erase"); + + count++; + } + + //ilog(" === erase"); + + while (_message_queue.begin()!=_message_queue.end()){ + + auto itr = _message_queue.end(); + itr--; + + _message_queue.erase(itr); + } + + //ilog(" === after erase"); + + if (memo!=""){ + ilog(" === ${memo} : ", ("memo", memo)); + } + + ilog(" === pacemaker dispatched ${proposals} proposals, ${votes} votes, ${new_blocks} new_blocks, ${new_views} new_views", + ("proposals", proposals_count) + ("votes", votes_count) + ("new_blocks", new_blocks_count) + ("new_views", new_views_count)); + + return dispatched_messages; + } + + void test_pacemaker::activate(name replica){ + auto qc_itr = _qcc_store.get().find( replica.to_uint64_t() ); + if (qc_itr==_qcc_store.end()) throw std::runtime_error("replica not found"); + _qcc_store.modify(qc_itr, [&]( auto& qcc ){ + qcc._active = true; + }); + } + + void test_pacemaker::deactivate(name replica){ + auto qc_itr = _qcc_store.get().find( replica.to_uint64_t() ); + if (qc_itr==_qcc_store.end()) throw std::runtime_error("replica not found"); + _qcc_store.modify(qc_itr, [&]( auto& qcc ){ + qcc._active = false; + }); + } + + name test_pacemaker::get_proposer(){ + return _proposer; + }; + + name test_pacemaker::get_leader(){ + return _leader; + }; + + name test_pacemaker::get_next_leader(){ + return _next_leader; + }; + + std::vector test_pacemaker::get_finalizers(){ + return _finalizers; + }; + + block_id_type test_pacemaker::get_current_block_id(){ + return _current_block_id; + }; + + uint32_t test_pacemaker::get_quorum_threshold(){ + return _quorum_threshold; + }; + + void test_pacemaker::beat(){ + auto itr = _qcc_store.get().find( _proposer.to_uint64_t() ); + if (itr==_qcc_store.end()) throw std::runtime_error("proposer not found"); + itr->_qc_chain->on_beat(); + }; + + void test_pacemaker::assign_qc_chain(name name, qc_chain& qcc){ + + //ilog("reg listener"); + + auto itr = _qcc_store.get().find( name.to_uint64_t() ); + + //ilog("got itr"); + + if (itr!=_qcc_store.end()){ + throw std::runtime_error("duplicate qc chain"); + } + else { + + //ilog("new listener ${name}", ("name", name)); + + //_unique_replicas.push_back(name); + + indexed_qc_chain iqcc; + + iqcc._name = name; + iqcc._active = true; + iqcc._qc_chain = &qcc; + + //ilog(" === register_listener 1 ${my_producers}", ("my_producers", iqcc._qc_chain->_my_producers)); + + _qcc_store.insert(iqcc); + + //auto itr = _qcc_store.get().find( name.to_uint64_t() ); + + //ilog(" === register_listener 2 ${my_producers}", ("my_producers", itr->_qc_chain->_my_producers)); + } + }; + + void test_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ + //ilog("queuing hs_proposal_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); + _pending_message_queue.push_back(std::make_pair(id, msg)); + }; + + void test_pacemaker::send_hs_vote_msg(name id, hs_vote_message msg){ + //ilog("queuing hs_vote_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); + _pending_message_queue.push_back(std::make_pair(id, msg)); + }; + + void test_pacemaker::send_hs_new_block_msg(name id, hs_new_block_message msg){ + _pending_message_queue.push_back(std::make_pair(id, msg)); + }; + + void test_pacemaker::send_hs_new_view_msg(name id, hs_new_view_message msg){ + _pending_message_queue.push_back(std::make_pair(id, msg)); + }; + + void test_pacemaker::on_hs_proposal_msg(name id, hs_proposal_message msg){ + //ilog(" === on_hs_proposal_msg"); + auto qc_itr = _qcc_store.begin(); + while (qc_itr!=_qcc_store.end()){ + //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); + + if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + + if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_proposal_msg(msg); + + qc_itr++; + } + //ilog(" === end on_hs_proposal_msg"); + } + + void test_pacemaker::on_hs_vote_msg(name id, hs_vote_message msg){ + //ilog(" === on_hs_vote_msg"); + auto qc_itr = _qcc_store.begin(); + while (qc_itr!=_qcc_store.end()){ + //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); + + if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + + if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_vote_msg(msg); + + qc_itr++; + } + //ilog(" === end on_hs_vote_msg"); + } + + void test_pacemaker::on_hs_new_block_msg(name id, hs_new_block_message msg){ + //ilog(" === on_hs_new_block_msg"); + auto qc_itr = _qcc_store.begin(); + while (qc_itr!=_qcc_store.end()){ + //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); + + if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + + if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_block_msg(msg); + + qc_itr++; + } + //ilog(" === end on_hs_new_block_msg"); + } + + void test_pacemaker::on_hs_new_view_msg(name id, hs_new_view_message msg){ + //ilog(" === on_hs_new_view_msg"); + auto qc_itr = _qcc_store.begin(); + while (qc_itr!=_qcc_store.end()){ + //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); + + if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + + if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_view_msg(msg); + + qc_itr++; + } + //ilog(" === end on_hs_new_view_msg"); + } + +}} From 5517d4b744ecaa44eafa0c7022bca1a5e5435cd5 Mon Sep 17 00:00:00 2001 From: fcecin Date: Thu, 13 Apr 2023 12:30:21 -0300 Subject: [PATCH 020/151] starting refactor --- .../chain/include/eosio/chain/hotstuff.hpp | 2 +- .../include/eosio/hotstuff/qc_chain.hpp | 5 --- .../include/eosio/hotstuff/test_pacemaker.hpp | 31 +++++++------------ libraries/hotstuff/test/test_hotstuff.cpp | 2 +- libraries/hotstuff/test_pacemaker.cpp | 24 ++++++++------ 5 files changed, 29 insertions(+), 35 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index be091882e4..d20875a139 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -78,7 +78,7 @@ namespace eosio { namespace chain { }} //eosio::chain -FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); +FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(quorum_met)(active_finalizers)(active_agg_sig)); FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(phase_counter)(parent_id)(final_on_qc)(justify)); FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify)); diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 1542d62e43..b661b8a7cd 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -171,11 +171,6 @@ namespace eosio { namespace hotstuff { }; - ~qc_chain(){ - _proposal_store.get().clear(); - _proposal_store.get().clear(); - }; - private: base_pacemaker* _pacemaker = nullptr; diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index 0578846c5d..04e14f92dc 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -9,17 +9,16 @@ namespace eosio { namespace hotstuff { //class-specific functions - class indexed_qc_chain { - public: - name _name; - bool _active = true; - qc_chain* _qc_chain = nullptr; //todo : use smart pointer + struct indexed_qc_chain { + name _name; + bool _active = true; + qc_chain* _qc_chain = nullptr; - uint64_t by_name()const{return _name.to_uint64_t();}; + uint64_t by_name() const { return _name.to_uint64_t(); }; - ~indexed_qc_chain(){ - _qc_chain = nullptr; - }; + indexed_qc_chain(const name & name, qc_chain* qc_chain, bool active = true) + : _name(name), _active(active), _qc_chain(qc_chain) { } + indexed_qc_chain() = delete; }; struct by_name_id{}; @@ -36,11 +35,6 @@ namespace eosio { namespace hotstuff { qc_chain_type _qcc_store; -/* void send_hs_proposal_msg(hs_proposal_message msg); - void send_hs_vote_msg(hs_vote_message msg); - void send_hs_new_block_msg(hs_new_block_message msg); - void send_hs_new_view_msg(hs_new_view_message msg);*/ - using hotstuff_message = std::pair>; //void init(std::vector unique_replicas); @@ -61,7 +55,10 @@ namespace eosio { namespace hotstuff { void pipe(std::vector messages); - std::vector dispatch(std::string memo, int count); + // Remove unused return value + //std::vector + void dispatch(std::string memo, int count); + std::vector dispatch(std::string memo); void activate(name replica); @@ -69,10 +66,6 @@ namespace eosio { namespace hotstuff { //indexed_qc_chain get_qc_chain(name replica); - ~test_pacemaker(){ - _qcc_store.get().clear(); - }; - //base_pacemaker interface functions name get_proposer(); diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 2a047a1d8b..ddde8132ce 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -21,7 +21,7 @@ std::vector ids{ block_id_type("00000001d49031dba775bd2b44fd339a3 block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530684"), block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf330")}; -std::vector alternate_ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c31"), +std::vector alternate_ids{ block_id_type("00000001d49031dba775bd2b44fd339a329ef462aaf019e5b75b4cd9609a0c31"), block_id_type("0000000202b23f86652ae43cba4bec5579c8c7133c14011a6f8d93b316530681"), block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf331")}; diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test_pacemaker.cpp index c7789b4063..7e82f2e008 100644 --- a/libraries/hotstuff/test_pacemaker.cpp +++ b/libraries/hotstuff/test_pacemaker.cpp @@ -39,7 +39,9 @@ namespace eosio { namespace hotstuff { } } - std::vector test_pacemaker::dispatch(std::string memo, int count){ + // Remove unused return value + //std::vector + void test_pacemaker::dispatch(std::string memo, int count){ for (int i = 0 ; i < count ; i++){ this->dispatch(memo); } @@ -182,11 +184,11 @@ namespace eosio { namespace hotstuff { //_unique_replicas.push_back(name); - indexed_qc_chain iqcc; + indexed_qc_chain iqcc(name, &qcc); - iqcc._name = name; - iqcc._active = true; - iqcc._qc_chain = &qcc; + //iqcc._name = name; + //iqcc._active = true; + //iqcc._qc_chain = &qcc; //ilog(" === register_listener 1 ${my_producers}", ("my_producers", iqcc._qc_chain->_my_producers)); @@ -222,7 +224,8 @@ namespace eosio { namespace hotstuff { while (qc_itr!=_qcc_store.end()){ //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + // never happens && redundant check + //if (qc_itr->_qc_chain == nullptr) throw std::runtime_error("ptr is null"); if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_proposal_msg(msg); @@ -237,7 +240,8 @@ namespace eosio { namespace hotstuff { while (qc_itr!=_qcc_store.end()){ //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + // never happens && redundant check + //if (qc_itr->_qc_chain == nullptr) throw std::runtime_error("ptr is null"); if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_vote_msg(msg); @@ -252,7 +256,8 @@ namespace eosio { namespace hotstuff { while (qc_itr!=_qcc_store.end()){ //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + // never happens && redundant check + //if (qc_itr->_qc_chain == nullptr) throw std::runtime_error("ptr is null"); if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_block_msg(msg); @@ -267,7 +272,8 @@ namespace eosio { namespace hotstuff { while (qc_itr!=_qcc_store.end()){ //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - if (qc_itr->_qc_chain == NULL) throw std::runtime_error("ptr is null"); + // never happens && redundant check + //if (qc_itr->_qc_chain == nullptr) throw std::runtime_error("ptr is null"); if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_view_msg(msg); From f55f0ebd64ceed7239d013e65639771d961bec51 Mon Sep 17 00:00:00 2001 From: fcecin Date: Fri, 14 Apr 2023 19:26:05 -0300 Subject: [PATCH 021/151] update hotstuff netcode, revert quorum_certificate FC_REFLECT change --- .../chain/include/eosio/chain/hotstuff.hpp | 2 +- plugins/net_plugin/net_plugin.cpp | 292 +++--------------- 2 files changed, 45 insertions(+), 249 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index d20875a139..be091882e4 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -78,7 +78,7 @@ namespace eosio { namespace chain { }} //eosio::chain -FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(quorum_met)(active_finalizers)(active_agg_sig)); +FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(phase_counter)(parent_id)(final_on_qc)(justify)); FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify)); diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index ec303c9f86..8c5633ef4a 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -219,10 +219,6 @@ namespace eosio { constexpr uint32_t signed_block_which = fc::get_index(); // see protocol net_message constexpr uint32_t packed_transaction_which = fc::get_index(); // see protocol net_message - constexpr uint32_t hs_vote_message_which = fc::get_index(); // see protocol net_message - constexpr uint32_t hs_proposal_message_which = fc::get_index(); // see protocol net_message - constexpr uint32_t hs_new_view_message_which = fc::get_index(); // see protocol net_message - constexpr uint32_t hs_new_block_message_which = fc::get_index(); // see protocol net_message class net_plugin_impl : public std::enable_shared_from_this, public auto_bp_peering::bp_connection_manager { @@ -719,11 +715,6 @@ namespace eosio { bool process_next_block_message(uint32_t message_length); bool process_next_trx_message(uint32_t message_length); - bool process_next_hs_proposal_message(uint32_t message_length); - bool process_next_hs_vote_message(uint32_t message_length); - bool process_next_hs_new_view_message(uint32_t message_length); - bool process_next_hs_new_block_message(uint32_t message_length); - public: bool populate_handshake( handshake_message& hello ); @@ -821,11 +812,11 @@ namespace eosio { void handle_message( const block_id_type& id, signed_block_ptr msg ); void handle_message( const packed_transaction& msg ) = delete; // packed_transaction_ptr overload used instead void handle_message( packed_transaction_ptr msg ); - void handle_message( const hs_vote_message_ptr& msg ); - void handle_message( const hs_proposal_message_ptr& msg ); - void handle_message( const hs_new_view_message_ptr& msg ); - void handle_message( const hs_new_block_message_ptr& msg ); + void handle_message( const hs_vote_message& msg ); + void handle_message( const hs_proposal_message& msg ); + void handle_message( const hs_new_view_message& msg ); + void handle_message( const hs_new_block_message& msg ); void process_signed_block( const block_id_type& id, signed_block_ptr msg, block_state_ptr bsp ); @@ -904,28 +895,28 @@ namespace eosio { c->handle_message( msg ); } - void operator()( const hs_vote_message_ptr& msg ) const { + void operator()( const hs_vote_message& msg ) const { // continue call to handle_message on connection strand - peer_dlog( c, "handle hs_vote_message_ptr" ); + peer_dlog( c, "handle hs_vote_message" ); c->handle_message( msg ); } - void operator()( const hs_proposal_message_ptr& msg ) const { + void operator()( const hs_proposal_message& msg ) const { // continue call to handle_message on connection strand - peer_dlog( c, "handle hs_proposal_message_ptr" ); + peer_dlog( c, "handle hs_proposal_message" ); c->handle_message( msg ); } - - void operator()( const hs_new_view_message_ptr& msg ) const { + void operator()( const hs_new_view_message& msg ) const { // continue call to handle_message on connection strand - peer_dlog( c, "handle hs_new_view_message_ptr" ); + peer_dlog( c, "handle hs_new_view_message" ); c->handle_message( msg ); } - void operator()( const hs_new_block_message_ptr& msg ) const { + void operator()( const hs_new_block_message& msg ) const { // continue call to handle_message on connection strand - peer_dlog( c, "handle hs_new_block_message_ptr" ); + peer_dlog( c, "handle hs_new_block_message" ); c->handle_message( msg ); } + }; @@ -1441,77 +1432,6 @@ namespace eosio { } }; - struct hs_proposal_message_buffer_factory : public buffer_factory { - - const send_buffer_type& get_send_buffer( const hs_proposal_message_ptr& sb ) { - if( !send_buffer ) { - send_buffer = create_send_buffer( sb ); - } - return send_buffer; - } - - private: - - static std::shared_ptr> create_send_buffer( const hs_proposal_message_ptr& sb ) { - static_assert( hs_proposal_message_which == fc::get_index() ); - fc_dlog( logger, "sending hs_proposal_message"); - return buffer_factory::create_send_buffer( hs_proposal_message_which, *sb ); - } - }; - - struct hs_vote_message_buffer_factory : public buffer_factory { - - const send_buffer_type& get_send_buffer( const hs_vote_message_ptr& sb ) { - if( !send_buffer ) { - send_buffer = create_send_buffer( sb ); - } - return send_buffer; - } - - private: - - static std::shared_ptr> create_send_buffer( const hs_vote_message_ptr& sb ) { - static_assert( hs_vote_message_which == fc::get_index() ); - fc_dlog( logger, "sending hs_vote_message"); - return buffer_factory::create_send_buffer( hs_vote_message_which, *sb ); - } - }; - - struct hs_new_view_message_buffer_factory : public buffer_factory { - - const send_buffer_type& get_send_buffer( const hs_new_view_message_ptr& sb ) { - if( !send_buffer ) { - send_buffer = create_send_buffer( sb ); - } - return send_buffer; - } - - private: - - static std::shared_ptr> create_send_buffer( const hs_new_view_message_ptr& sb ) { - static_assert( hs_new_view_message_which == fc::get_index() ); - fc_dlog( logger, "sending hs_new_view_message"); - return buffer_factory::create_send_buffer( hs_new_view_message_which, *sb ); - } - }; - - struct hs_new_block_message_buffer_factory : public buffer_factory { - - const send_buffer_type& get_send_buffer( const hs_new_block_message_ptr& sb ) { - if( !send_buffer ) { - send_buffer = create_send_buffer( sb ); - } - return send_buffer; - } - - private: - - static std::shared_ptr> create_send_buffer( const hs_new_block_message_ptr& sb ) { - static_assert( hs_new_block_message_which == fc::get_index() ); - fc_dlog( logger, "sending hs_new_block_message"); - return buffer_factory::create_send_buffer( hs_new_block_message_which, *sb ); - } - }; struct trx_buffer_factory : public buffer_factory { /// caches result for subsequent calls, only provide same packed_transaction_ptr instance for each invocation. @@ -2276,20 +2196,11 @@ namespace eosio { void dispatch_manager::bcast_hs_proposal_msg(const hs_proposal_message_ptr& msg) { if( my_impl->sync_master->syncing_with_peer() ) return; - - hs_proposal_message_buffer_factory buff_factory; - - for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { - + hs_proposal_message & msg_val = *(msg.get()); + for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; - send_buffer_type sb = buff_factory.get_send_buffer( msg ); - - cp->strand.post( [this, cp, sb{std::move(sb)}]() { - std::unique_lock g_conn( cp->conn_mtx ); - g_conn.unlock(); - - cp->enqueue_buffer( sb, no_reason ); - + cp->strand.post( [this, cp, msg_val]() { + cp->enqueue( msg_val ); }); return true; } ); @@ -2297,20 +2208,11 @@ namespace eosio { void dispatch_manager::bcast_hs_vote_msg(const hs_vote_message_ptr& msg) { if( my_impl->sync_master->syncing_with_peer() ) return; - - hs_vote_message_buffer_factory buff_factory; - - for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { - + hs_vote_message & msg_val = *(msg.get()); + for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; - send_buffer_type sb = buff_factory.get_send_buffer( msg ); - - cp->strand.post( [this, cp, sb{std::move(sb)}]() { - std::unique_lock g_conn( cp->conn_mtx ); - g_conn.unlock(); - - cp->enqueue_buffer( sb, no_reason ); - + cp->strand.post( [this, cp, msg_val]() { + cp->enqueue( msg_val ); }); return true; } ); @@ -2318,20 +2220,11 @@ namespace eosio { void dispatch_manager::bcast_hs_new_block_msg(const hs_new_block_message_ptr& msg) { if( my_impl->sync_master->syncing_with_peer() ) return; - - hs_new_block_message_buffer_factory buff_factory; - - for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { - + hs_new_block_message & msg_val = *(msg.get()); + for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; - send_buffer_type sb = buff_factory.get_send_buffer( msg ); - - cp->strand.post( [this, cp, sb{std::move(sb)}]() { - std::unique_lock g_conn( cp->conn_mtx ); - g_conn.unlock(); - - cp->enqueue_buffer( sb, no_reason ); - + cp->strand.post( [this, cp, msg_val]() { + cp->enqueue( msg_val ); }); return true; } ); @@ -2339,20 +2232,11 @@ namespace eosio { void dispatch_manager::bcast_hs_new_view_msg(const hs_new_view_message_ptr& msg) { if( my_impl->sync_master->syncing_with_peer() ) return; - - hs_new_view_message_buffer_factory buff_factory; - - for_each_block_connection( [this, &msg, &buff_factory]( auto& cp ) { - + hs_new_view_message & msg_val = *(msg.get()); + for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; - send_buffer_type sb = buff_factory.get_send_buffer( msg ); - - cp->strand.post( [this, cp, sb{std::move(sb)}]() { - std::unique_lock g_conn( cp->conn_mtx ); - g_conn.unlock(); - - cp->enqueue_buffer( sb, no_reason ); - + cp->strand.post( [this, cp, msg_val]() { + cp->enqueue( msg_val ); }); return true; } ); @@ -2773,31 +2657,13 @@ namespace eosio { auto peek_ds = pending_message_buffer.create_peek_datastream(); unsigned_int which{}; fc::raw::unpack( peek_ds, which ); + if( which == signed_block_which ) { latest_blk_time = get_time(); return process_next_block_message( message_length ); - } else if( which == packed_transaction_which ) { return process_next_trx_message( message_length ); - - } else if( which == hs_vote_message_which ) { - //ilog("process_next_message : process_next_hs_vote_message"); - return process_next_hs_vote_message( message_length ); - - } else if( which == hs_proposal_message_which ) { - //ilog("process_next_message : process_next_hs_proposal_message"); - return process_next_hs_proposal_message( message_length ); - - } else if( which == hs_new_view_message_which ) { - //ilog("process_next_message : process_next_hs_new_view_message"); - return process_next_hs_new_view_message( message_length ); - - } else if( which == hs_new_block_message_which ) { - //ilog("process_next_message : process_next_hs_new_block_message"); - return process_next_hs_new_block_message( message_length ); - } else { - //ilog("process_next_message : other"); auto ds = pending_message_buffer.create_datastream(); net_message msg; fc::raw::unpack( ds, msg ); @@ -2813,82 +2679,6 @@ namespace eosio { return true; } - bool connection::process_next_hs_vote_message(uint32_t message_length){ - - auto peek_ds = pending_message_buffer.create_peek_datastream(); - unsigned_int which{}; - fc::raw::unpack( peek_ds, which ); // throw away - - hs_vote_message cm; - fc::raw::unpack( peek_ds, cm ); - - auto ds = pending_message_buffer.create_datastream(); - fc::raw::unpack( ds, which ); - shared_ptr ptr = std::make_shared(); - fc::raw::unpack( ds, *ptr ); - - handle_message(std::move( ptr ) ); - - return true; - } - - bool connection::process_next_hs_proposal_message(uint32_t message_length){ - - auto peek_ds = pending_message_buffer.create_peek_datastream(); - unsigned_int which{}; - fc::raw::unpack( peek_ds, which ); // throw away - - hs_proposal_message cm; - fc::raw::unpack( peek_ds, cm ); - - auto ds = pending_message_buffer.create_datastream(); - fc::raw::unpack( ds, which ); - shared_ptr ptr = std::make_shared(); - fc::raw::unpack( ds, *ptr ); - - handle_message(std::move( ptr ) ); - - return true; - } - - bool connection::process_next_hs_new_view_message(uint32_t message_length){ - - auto peek_ds = pending_message_buffer.create_peek_datastream(); - unsigned_int which{}; - fc::raw::unpack( peek_ds, which ); // throw away - - hs_new_view_message cm; - fc::raw::unpack( peek_ds, cm ); - - auto ds = pending_message_buffer.create_datastream(); - fc::raw::unpack( ds, which ); - shared_ptr ptr = std::make_shared(); - fc::raw::unpack( ds, *ptr ); - - handle_message(std::move( ptr ) ); - - return true; - } - - bool connection::process_next_hs_new_block_message(uint32_t message_length){ - - auto peek_ds = pending_message_buffer.create_peek_datastream(); - unsigned_int which{}; - fc::raw::unpack( peek_ds, which ); // throw away - - hs_new_block_message cm; - fc::raw::unpack( peek_ds, cm ); - - auto ds = pending_message_buffer.create_datastream(); - fc::raw::unpack( ds, which ); - shared_ptr ptr = std::make_shared(); - fc::raw::unpack( ds, *ptr ); - - handle_message(std::move( ptr ) ); - - return true; - } - // called from connection strand bool connection::process_next_block_message(uint32_t message_length) { auto peek_ds = pending_message_buffer.create_peek_datastream(); @@ -3452,42 +3242,46 @@ namespace eosio { } } - void connection::handle_message( const hs_vote_message_ptr& msg ) { + void connection::handle_message( const hs_vote_message& msg ) { //peer_ilog( this, "received confirmation message" ); //ilog("received confirmation message"); if (my_impl->producer_plug != nullptr){ - my_impl->producer_plug->notify_hs_vote_message(msg); + hs_vote_message_ptr msg_ptr = std::make_shared(msg); + my_impl->producer_plug->notify_hs_vote_message(msg_ptr); } } - void connection::handle_message( const hs_proposal_message_ptr& msg ) { + void connection::handle_message( const hs_proposal_message& msg ) { //peer_ilog( this, "received consensus message" ); //ilog("received consensus message"); if (my_impl->producer_plug != nullptr){ - my_impl->producer_plug->notify_hs_proposal_message(msg); + hs_proposal_message_ptr msg_ptr = std::make_shared(msg); + my_impl->producer_plug->notify_hs_proposal_message(msg_ptr); } } - void connection::handle_message( const hs_new_view_message_ptr& msg ) { + void connection::handle_message( const hs_new_view_message& msg ) { //peer_ilog( this, "received new view message" ); //ilog("received new view message"); if (my_impl->producer_plug != nullptr){ - my_impl->producer_plug->notify_hs_new_view_message(msg); + hs_new_view_message_ptr msg_ptr = std::make_shared(msg); + my_impl->producer_plug->notify_hs_new_view_message(msg_ptr); } } - void connection::handle_message( const hs_new_block_message_ptr& msg ) { + void connection::handle_message( const hs_new_block_message& msg ) { //peer_ilog( this, "received new block message" ); //ilog("received new block message"); if (my_impl->producer_plug != nullptr){ - my_impl->producer_plug->notify_hs_new_block_message(msg); + hs_new_block_message_ptr msg_ptr = std::make_shared(msg); + my_impl->producer_plug->notify_hs_new_block_message(msg_ptr); } } @@ -4233,6 +4027,7 @@ namespace eosio { cc.irreversible_block.connect( [my = my]( const block_state_ptr& s ) { my->on_irreversible_block( s ); } ); + cc.new_hs_proposal_message.connect( [my = my]( const hs_proposal_message_ptr& s ) { my->on_hs_proposal_message( s ); } ); @@ -4245,6 +4040,7 @@ namespace eosio { cc.new_hs_new_block_message.connect( [my = my]( const hs_new_block_message_ptr& s ) { my->on_hs_new_block_message( s ); } ); + } { From 0b6933e73eaee67180eb8ebfa3242f615b7d2d8c Mon Sep 17 00:00:00 2001 From: fcecin Date: Wed, 19 Apr 2023 11:36:45 -0300 Subject: [PATCH 022/151] hscore profiler; _b_leaf send_proposal fix --- libraries/hotstuff/chain_pacemaker.cpp | 112 +++++++++++++++++++++++++ libraries/hotstuff/qc_chain.cpp | 8 +- 2 files changed, 116 insertions(+), 4 deletions(-) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index a1646d8a64..e830342177 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -1,8 +1,105 @@ #include #include +// comment this out to remove the core profiler +#define HS_CORE_PROFILER + namespace eosio { namespace hotstuff { +// ======================== Core profiling instrumentation ========================= +#ifdef HS_CORE_PROFILER + std::mutex csc_mutex; + bool csc_started = false; + fc::microseconds csc_total; // total time spent by all net threads waiting on the core lock + fc::time_point csc_first_time; // first time the core has received a request + fc::time_point csc_last_report_time; // last time a core timing report was printed to the log + int64_t csc_reqs; // total number of times the core has been entered by a net thread + struct reqstat { // per-core-request-type stats + fc::microseconds total_us; // total time spent in this request type + fc::microseconds max_us; // maximum time ever spent inside a request of this type + int64_t count = 0; // total requests of this type made + }; + std::map reqs; + class csc { + public: + fc::time_point start; // time lock request was made + fc::time_point start_core; // time the core has been entered + std::string name; + csc(const std::string & entrypoint_name) : + start(fc::time_point::now()), name(entrypoint_name) { } + void core_in() { + start_core = fc::time_point::now(); + std::lock_guard g( csc_mutex ); + ++csc_reqs; // update total core requests + csc_total += start_core - start; // update total core synchronization contention time + if (! csc_started) { // one-time initialization + csc_started = true; + csc_first_time = start_core; + csc_last_report_time = start_core; + } + } + void core_out() { + fc::time_point end = fc::time_point::now(); + std::lock_guard g( csc_mutex ); + + // update per-request metrics + { + auto it = reqs.find(name); + if (it == reqs.end()) { + reqs.insert({name, reqstat()}); + it = reqs.find(name); + } + reqstat &req = it->second; + ++req.count; + fc::microseconds exectime = end - start_core; + req.total_us += exectime; + if (exectime > req.max_us) { + req.max_us = exectime; + } + } + + // emit full report every 10s + fc::microseconds elapsed = end - csc_last_report_time; + if (elapsed.count() > 10000000) { // 10-second intervals to print the report + fc::microseconds total_us = end - csc_first_time; // total testing walltime so far since 1st request seen + int64_t total_secs = total_us.count() / 1000000; // never zero if report interval large enough + int64_t avgs = csc_total.count() / total_secs; + int64_t avgr = csc_total.count() / csc_reqs; + // core contention report + ilog("HS-CORE: csc_total_us:${tot} csc_elapsed_s:${secs} csc_avg_us_per_s:${avgs} csc_reqs:${reqs} csc_avg_us_per_req:${avgr}", ("tot", csc_total)("secs",total_secs)("avgs", avgs)("reqs", csc_reqs)("avgr", avgr)); + fc::microseconds req_total_us; // will compute global stats for all request types + fc::microseconds req_max_us; + int64_t req_count = 0; + auto it = reqs.begin(); + while (it != reqs.end()) { + const std::string & req_name = it->first; + reqstat &req = it->second; + int64_t avgr = req.total_us.count() / it->second.count; + // per-request-type performance report + ilog("HS-CORE: ${rn}_total_us:${tot} ${rn}_max_us:${max} ${rn}_reqs:${reqs} ${rn}_avg_us_per_req:${avgr}", ("rn",req_name)("tot", req.total_us)("max",req.max_us)("reqs", req.count)("avgr", avgr)); + req_total_us += req.total_us; + if (req_max_us < req.max_us) { + req_max_us = req.max_us; + } + req_count += req.count; + ++it; + } + // combined performance report + int64_t req_avgr = req_total_us.count() / req_count; + ilog("HS-CORE: total_us:${tot} max_us:${max} reqs:${reqs} avg_us_per_req:${avgr}", ("tot", req_total_us)("max",req_max_us)("reqs", req_count)("avgr", req_avgr)); + csc_last_report_time = end; + } + } + }; +#else + struct csc { // dummy profiler + csc(const string & s) { } + void core_in() { } + void core_out() { } + } +#endif +//=============================================================================================== + void chain_pacemaker::init(controller* chain){ _chain = chain; } @@ -45,8 +142,11 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::beat(){ + csc prof("beat"); std::lock_guard g( this-> _hotstuff_state_mutex ); + prof.core_in(); _qc_chain->on_beat(); + prof.core_out(); } void chain_pacemaker::assign_qc_chain(name name, qc_chain& qcc){ @@ -74,23 +174,35 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_proposal_msg(name id, hs_proposal_message msg){ + csc prof("prop"); std::lock_guard g( this-> _hotstuff_state_mutex ); + prof.core_in(); _qc_chain->on_hs_proposal_msg(msg); + prof.core_out(); } void chain_pacemaker::on_hs_vote_msg(name id, hs_vote_message msg){ + csc prof("vote"); std::lock_guard g( this-> _hotstuff_state_mutex ); + prof.core_in(); _qc_chain->on_hs_vote_msg(msg); + prof.core_out(); } void chain_pacemaker::on_hs_new_block_msg(name id, hs_new_block_message msg){ + csc prof("nblk"); std::lock_guard g( this-> _hotstuff_state_mutex ); + prof.core_in(); _qc_chain->on_hs_new_block_msg(msg); + prof.core_out(); } void chain_pacemaker::on_hs_new_view_msg(name id, hs_new_view_message msg){ + csc prof("view"); std::lock_guard g( this-> _hotstuff_state_mutex ); + prof.core_in(); _qc_chain->on_hs_new_view_msg(msg); + prof.core_out(); } }} diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index d757cc35a7..15bd08258b 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -430,10 +430,10 @@ namespace eosio { namespace hotstuff { //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); _pending_proposal_block = NULL_BLOCK_ID; - send_hs_proposal_msg(proposal_candidate); - _b_leaf = proposal_candidate.proposal_id; + send_hs_proposal_msg(proposal_candidate); + //if (_log) ilog(" === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); } } @@ -570,10 +570,10 @@ namespace eosio { namespace hotstuff { _pending_proposal_block = NULL_BLOCK_ID; - send_hs_proposal_msg(proposal_candidate); - _b_leaf = proposal_candidate.proposal_id; + send_hs_proposal_msg(proposal_candidate); + //if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); } } From f3409f37fe080d79484e86a817c81fb2544b1b69 Mon Sep 17 00:00:00 2001 From: fcecin Date: Thu, 20 Apr 2023 16:55:27 -0300 Subject: [PATCH 023/151] IF proto version; fix localhost send vote msg; hs-core optimizations --- .../chain/include/eosio/chain/hotstuff.hpp | 6 +- libraries/hotstuff/chain_pacemaker.cpp | 16 ++-- .../include/eosio/hotstuff/base_pacemaker.hpp | 16 ++-- .../eosio/hotstuff/chain_pacemaker.hpp | 18 ++-- .../include/eosio/hotstuff/qc_chain.hpp | 41 ++++----- .../include/eosio/hotstuff/test_pacemaker.hpp | 18 ++-- libraries/hotstuff/qc_chain.cpp | 85 ++++++++++++------- libraries/hotstuff/test_pacemaker.cpp | 16 ++-- .../include/eosio/net_plugin/protocol.hpp | 12 +-- plugins/net_plugin/net_plugin.cpp | 15 ++-- 10 files changed, 134 insertions(+), 109 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index be091882e4..6e99026037 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -27,9 +27,9 @@ namespace eosio { namespace chain { struct quorum_certificate { fc::sha256 proposal_id = NULL_PROPOSAL_ID; - bool quorum_met = false; fc::unsigned_int active_finalizers; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; + bool quorum_met = false; }; struct hs_vote_message { @@ -43,10 +43,10 @@ namespace eosio { namespace chain { struct hs_proposal_message { fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal block_id_type block_id = NULL_BLOCK_ID; - uint8_t phase_counter = 0; fc::sha256 parent_id = NULL_PROPOSAL_ID; //new proposal fc::sha256 final_on_qc = NULL_PROPOSAL_ID; quorum_certificate justify; //justification + uint8_t phase_counter = 0; hs_proposal_message() = default; @@ -80,6 +80,6 @@ namespace eosio { namespace chain { FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); -FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(phase_counter)(parent_id)(final_on_qc)(justify)); +FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(parent_id)(final_on_qc)(justify)(phase_counter)); FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify)); FC_REFLECT(eosio::chain::hs_new_view_message, (high_qc)); diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index e830342177..98c73d7d35 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -153,27 +153,27 @@ namespace eosio { namespace hotstuff { _qc_chain = &qcc; } - void chain_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ + void chain_pacemaker::send_hs_proposal_msg(name id, const hs_proposal_message & msg){ hs_proposal_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_proposal_msg(msg_ptr); } - void chain_pacemaker::send_hs_vote_msg(name id, hs_vote_message msg){ + void chain_pacemaker::send_hs_vote_msg(name id, const hs_vote_message & msg){ hs_vote_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_vote_msg(msg_ptr); } - void chain_pacemaker::send_hs_new_block_msg(name id, hs_new_block_message msg){ + void chain_pacemaker::send_hs_new_block_msg(name id, const hs_new_block_message & msg){ hs_new_block_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_new_block_msg(msg_ptr); } - void chain_pacemaker::send_hs_new_view_msg(name id, hs_new_view_message msg){ + void chain_pacemaker::send_hs_new_view_msg(name id, const hs_new_view_message & msg){ hs_new_view_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_new_view_msg(msg_ptr); } - void chain_pacemaker::on_hs_proposal_msg(name id, hs_proposal_message msg){ + void chain_pacemaker::on_hs_proposal_msg(name id, const hs_proposal_message & msg){ csc prof("prop"); std::lock_guard g( this-> _hotstuff_state_mutex ); prof.core_in(); @@ -181,7 +181,7 @@ namespace eosio { namespace hotstuff { prof.core_out(); } - void chain_pacemaker::on_hs_vote_msg(name id, hs_vote_message msg){ + void chain_pacemaker::on_hs_vote_msg(name id, const hs_vote_message & msg){ csc prof("vote"); std::lock_guard g( this-> _hotstuff_state_mutex ); prof.core_in(); @@ -189,7 +189,7 @@ namespace eosio { namespace hotstuff { prof.core_out(); } - void chain_pacemaker::on_hs_new_block_msg(name id, hs_new_block_message msg){ + void chain_pacemaker::on_hs_new_block_msg(name id, const hs_new_block_message & msg){ csc prof("nblk"); std::lock_guard g( this-> _hotstuff_state_mutex ); prof.core_in(); @@ -197,7 +197,7 @@ namespace eosio { namespace hotstuff { prof.core_out(); } - void chain_pacemaker::on_hs_new_view_msg(name id, hs_new_view_message msg){ + void chain_pacemaker::on_hs_new_view_msg(name id, const hs_new_view_message & msg){ csc prof("view"); std::lock_guard g( this-> _hotstuff_state_mutex ); prof.core_in(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index 301ce14869..a095dc3dc6 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -35,16 +35,16 @@ namespace eosio { namespace hotstuff { virtual void assign_qc_chain(name name, qc_chain& qcc) = 0; //outbound communications - virtual void send_hs_proposal_msg(name id, hs_proposal_message msg) = 0; - virtual void send_hs_vote_msg(name id, hs_vote_message msg) = 0; - virtual void send_hs_new_block_msg(name id, hs_new_block_message msg) = 0; - virtual void send_hs_new_view_msg(name id, hs_new_view_message msg) = 0; + virtual void send_hs_proposal_msg(name id, const hs_proposal_message & msg) = 0; + virtual void send_hs_vote_msg(name id, const hs_vote_message & msg) = 0; + virtual void send_hs_new_block_msg(name id, const hs_new_block_message & msg) = 0; + virtual void send_hs_new_view_msg(name id, const hs_new_view_message & msg) = 0; //inbound communications - virtual void on_hs_vote_msg(name id, hs_vote_message msg) = 0; //confirmation msg event handler - virtual void on_hs_proposal_msg(name id, hs_proposal_message msg) = 0; //consensus msg event handler - virtual void on_hs_new_view_msg(name id, hs_new_view_message msg) = 0; //new view msg event handler - virtual void on_hs_new_block_msg(name id, hs_new_block_message msg) = 0; //new block msg event handler + virtual void on_hs_vote_msg(name id, const hs_vote_message & msg) = 0; //confirmation msg event handler + virtual void on_hs_proposal_msg(name id, const hs_proposal_message & msg) = 0; //consensus msg event handler + virtual void on_hs_new_view_msg(name id, const hs_new_view_message & msg) = 0; //new view msg event handler + virtual void on_hs_new_block_msg(name id, const hs_new_block_message & msg) = 0; //new block msg event handler }; }} diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index c25240e600..2e905a687f 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -30,15 +30,15 @@ namespace eosio { namespace hotstuff { void beat(); - void send_hs_proposal_msg(name id, hs_proposal_message msg); - void send_hs_vote_msg(name id, hs_vote_message msg); - void send_hs_new_block_msg(name id, hs_new_block_message msg); - void send_hs_new_view_msg(name id, hs_new_view_message msg); - - void on_hs_vote_msg(name id, hs_vote_message msg); //confirmation msg event handler - void on_hs_proposal_msg(name id, hs_proposal_message msg); //consensus msg event handler - void on_hs_new_view_msg(name id, hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(name id, hs_new_block_message msg); //new block msg event handler + void send_hs_proposal_msg(name id, const hs_proposal_message & msg); + void send_hs_vote_msg(name id, const hs_vote_message & msg); + void send_hs_new_block_msg(name id, const hs_new_block_message & msg); + void send_hs_new_view_msg(name id, const hs_new_view_message & msg); + + void on_hs_vote_msg(name id, const hs_vote_message & msg); //confirmation msg event handler + void on_hs_proposal_msg(name id, const hs_proposal_message & msg); //consensus msg event handler + void on_hs_new_view_msg(name id, const hs_new_view_message & msg); //new view msg event handler + void on_hs_new_block_msg(name id, const hs_new_block_message & msg); //new block msg event handler private: diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index b661b8a7cd..9d9580e212 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -113,13 +113,14 @@ namespace eosio { namespace hotstuff { void reset_qc(fc::sha256 proposal_id); //reset current internal qc - bool evaluate_quorum(extended_schedule es, fc::unsigned_int finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal); //evaluate quorum for a proposal + bool evaluate_quorum(const extended_schedule & es, fc::unsigned_int finalizers, const fc::crypto::blslib::bls_signature & agg_sig, const hs_proposal_message & proposal); //evaluate quorum for a proposal /* name get_proposer(); name get_leader(); name get_incoming_leader(); //get incoming leader*/ - bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); //check if quorum has been met over a proposal + // qc.quorum_met has to be updated by the caller (if it wants to) based on the return value of this method + bool is_quorum_met(const eosio::chain::quorum_certificate & qc, const extended_schedule & schedule, const hs_proposal_message & proposal); //check if quorum has been met over a proposal std::vector get_finalizers(); //get current finalizers set @@ -132,43 +133,43 @@ namespace eosio { namespace hotstuff { bool am_i_leader(); //check if I am the current leader bool am_i_finalizer(); //check if I am one of the current finalizers - void process_proposal(hs_proposal_message msg); //handles proposal - void process_vote(hs_vote_message msg); //handles vote - void process_new_view(hs_new_view_message msg); //handles new view - void process_new_block(hs_new_block_message msg); //handles new block + void process_proposal(const hs_proposal_message & msg); //handles proposal + void process_vote(const hs_vote_message & msg); //handles vote + void process_new_view(const hs_new_view_message & msg); //handles new view + void process_new_block(const hs_new_block_message & msg); //handles new block - hs_vote_message sign_proposal(hs_proposal_message proposal, name finalizer); //sign proposal + hs_vote_message sign_proposal(const hs_proposal_message & proposal, name finalizer); //sign proposal bool extends(fc::sha256 descendant, fc::sha256 ancestor); //verify that a proposal descends from another void on_beat(); //handler for pacemaker beat() - void update_high_qc(eosio::chain::quorum_certificate high_qc); //check if update to our high qc is required + // returns true if quorum_met was recalculated in this call and it evaluated to true; returns false in all other cases + bool update_high_qc(const eosio::chain::quorum_certificate & high_qc); //check if update to our high qc is required void leader_rotation_check(); //check if leader rotation is required - bool is_node_safe(hs_proposal_message proposal); //verify if a proposal should be signed + bool is_node_safe(const hs_proposal_message & proposal); //verify if a proposal should be signed std::vector get_qc_chain(fc::sha256 proposal_id); //get 3-phase proposal justification - void send_hs_proposal_msg(hs_proposal_message msg); //send vote msg - void send_hs_vote_msg(hs_vote_message msg); //send proposal msg - void send_hs_new_view_msg(hs_new_view_message msg); //send new view msg - void send_hs_new_block_msg(hs_new_block_message msg); //send new block msg + void send_hs_proposal_msg(const hs_proposal_message & msg); //send vote msg + void send_hs_vote_msg(const hs_vote_message & msg); //send proposal msg + void send_hs_new_view_msg(const hs_new_view_message & msg); //send new view msg + void send_hs_new_block_msg(const hs_new_block_message & msg); //send new block msg - void on_hs_vote_msg(hs_vote_message msg); //vote msg event handler - void on_hs_proposal_msg(hs_proposal_message msg); //proposal msg event handler - void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler + void on_hs_vote_msg(const hs_vote_message & msg); //vote msg event handler + void on_hs_proposal_msg(const hs_proposal_message & msg); //proposal msg event handler + void on_hs_new_view_msg(const hs_new_view_message & msg); //new view msg event handler + void on_hs_new_block_msg(const hs_new_block_message & msg); //new block msg event handler - void update(hs_proposal_message proposal); //update internal state - void commit(hs_proposal_message proposal); //commit proposal (finality) + void update(const hs_proposal_message & proposal); //update internal state + void commit(const hs_proposal_message & proposal); //commit proposal (finality) void gc_proposals(uint64_t cutoff); //garbage collection of old proposals qc_chain(){ //ilog("_high_qc : ${qc_id}", ("qc_id", _high_qc.proposal_id)); - }; private: diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index 04e14f92dc..04fa265942 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -81,15 +81,15 @@ namespace eosio { namespace hotstuff { void beat(); - void send_hs_proposal_msg(name id, hs_proposal_message msg); - void send_hs_vote_msg(name id, hs_vote_message msg); - void send_hs_new_block_msg(name id, hs_new_block_message msg); - void send_hs_new_view_msg(name id, hs_new_view_message msg); - - void on_hs_vote_msg(name id, hs_vote_message msg); //confirmation msg event handler - void on_hs_proposal_msg(name id, hs_proposal_message msg); //consensus msg event handler - void on_hs_new_view_msg(name id, hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(name id, hs_new_block_message msg); //new block msg event handler + void send_hs_proposal_msg(name id, const hs_proposal_message & msg); + void send_hs_vote_msg(name id, const hs_vote_message & msg); + void send_hs_new_block_msg(name id, const hs_new_block_message & msg); + void send_hs_new_view_msg(name id, const hs_new_view_message & msg); + + void on_hs_vote_msg(name id, const hs_vote_message & msg); //confirmation msg event handler + void on_hs_proposal_msg(name id, const hs_proposal_message & msg); //consensus msg event handler + void on_hs_new_view_msg(name id, const hs_new_view_message & msg); //new view msg event handler + void on_hs_new_block_msg(name id, const hs_new_block_message & msg); //new block msg event handler std::vector _pending_message_queue; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 15bd08258b..bec32bdbca 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -148,7 +148,7 @@ namespace eosio { namespace hotstuff { return b; } - bool qc_chain::evaluate_quorum(extended_schedule es, fc::unsigned_int finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ + bool qc_chain::evaluate_quorum(const extended_schedule & es, fc::unsigned_int finalizers, const fc::crypto::blslib::bls_signature & agg_sig, const hs_proposal_message & proposal){ bool first = true; @@ -170,9 +170,13 @@ namespace eosio { namespace hotstuff { } } - fc::crypto::blslib::bls_signature justification_agg_sig; - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; + // **************************************************************************************************** + // FIXME/TODO/REVIEW: I removed this since it doesn't seem to be doing anything at the moment + // **************************************************************************************************** + // + //fc::crypto::blslib::bls_signature justification_agg_sig; + // + //if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); @@ -183,19 +187,21 @@ namespace eosio { namespace hotstuff { return ok; } - bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ + bool qc_chain::is_quorum_met(const eosio::chain::quorum_certificate & qc, const extended_schedule & schedule, const hs_proposal_message & proposal){ - if (qc.quorum_met == true ) { + if (qc.quorum_met) { return true; //skip evaluation if we've already verified quorum was met } else { //ilog(" === qc : ${qc}", ("qc", qc)); - bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); - - qc.quorum_met = quorum_met; - - return qc.quorum_met; + // Caller has to update the quorum_met flag on its qc object based on the return value of this method -- fcecin + // + //bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); + //qc.quorum_met = quorum_met; + //return qc.quorum_met; + // + return evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); } } @@ -239,7 +245,7 @@ namespace eosio { namespace hotstuff { return false; } - hs_vote_message qc_chain::sign_proposal(hs_proposal_message proposal, name finalizer){ + hs_vote_message qc_chain::sign_proposal(const hs_proposal_message & proposal, name finalizer){ _v_height = proposal.get_height(); @@ -253,7 +259,7 @@ namespace eosio { namespace hotstuff { return v_msg; } - void qc_chain::process_proposal(hs_proposal_message proposal){ + void qc_chain::process_proposal(const hs_proposal_message & proposal){ //auto start = fc::time_point::now(); @@ -318,6 +324,8 @@ namespace eosio { namespace hotstuff { bool node_safe = is_node_safe(proposal); bool signature_required = am_finalizer && node_safe; + std::vector msgs; + if (signature_required){ //iterate over all my finalizers and sign / broadcast for each that is in the schedule @@ -339,7 +347,8 @@ namespace eosio { namespace hotstuff { ("phase_counter", proposal.phase_counter) ("proposal_id", proposal.proposal_id));*/ - send_hs_vote_msg(v_msg); + //send_hs_vote_msg(v_msg); + msgs.push_back(v_msg); }; @@ -356,6 +365,10 @@ namespace eosio { namespace hotstuff { //update internal state update(proposal); + for (auto &msg : msgs){ + send_hs_vote_msg(msg); + } + //check for leader change leader_rotation_check(); @@ -363,7 +376,7 @@ namespace eosio { namespace hotstuff { //if (_log) ilog(" ... process_proposal() total time : ${total_time}", ("total_time", total_time)); } - void qc_chain::process_vote(hs_vote_message vote){ + void qc_chain::process_vote(const hs_vote_message & vote){ //auto start = fc::time_point::now(); @@ -443,36 +456,36 @@ namespace eosio { namespace hotstuff { //if (_log) ilog(" ... process_vote() total time : ${total_time}", ("total_time", total_time)); } - void qc_chain::process_new_view(hs_new_view_message new_view){ + void qc_chain::process_new_view(const hs_new_view_message & msg){ //if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", new_view.high_qc)("id", _id)); - update_high_qc(new_view.high_qc); + update_high_qc(msg.high_qc); } - void qc_chain::process_new_block(hs_new_block_message msg){ + void qc_chain::process_new_block(const hs_new_block_message & msg){ //ilog(" === Process new block ==="); } - void qc_chain::send_hs_proposal_msg(hs_proposal_message msg){ + void qc_chain::send_hs_proposal_msg(const hs_proposal_message & msg){ //ilog(" === broadcast_hs_proposal ==="); //hs_proposal_message_ptr ptr = std::make_shared(msg); _pacemaker->send_hs_proposal_msg(_id, msg); process_proposal(msg); } - void qc_chain::send_hs_vote_msg(hs_vote_message msg){ + void qc_chain::send_hs_vote_msg(const hs_vote_message & msg){ //ilog(" === broadcast_hs_vote ==="); //hs_vote_message_ptr ptr = std::make_shared(msg); _pacemaker->send_hs_vote_msg(_id, msg); process_vote(msg); } - void qc_chain::send_hs_new_view_msg(hs_new_view_message msg){ + void qc_chain::send_hs_new_view_msg(const hs_new_view_message & msg){ //ilog(" === broadcast_hs_new_view ==="); //hs_new_view_message_ptr ptr = std::make_shared(msg); _pacemaker->send_hs_new_view_msg(_id, msg); } - void qc_chain::send_hs_new_block_msg(hs_new_block_message msg){ + void qc_chain::send_hs_new_block_msg(const hs_new_block_message & msg){ //ilog(" === broadcast_hs_new_block ==="); //hs_new_block_message_ptr ptr = std::make_shared(msg); _pacemaker->send_hs_new_block_msg(_id, msg); @@ -599,7 +612,7 @@ namespace eosio { namespace hotstuff { handle_eptr(eptr); } - void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ + bool qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ //ilog(" === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); // if new high QC is higher than current, update to new @@ -619,8 +632,8 @@ namespace eosio { namespace hotstuff { old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); - if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); - if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); + if (old_high_qc_prop == _proposal_store.get().end()) return false; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); + if (new_high_qc_prop == _proposal_store.get().end()) return false; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ @@ -628,17 +641,23 @@ namespace eosio { namespace hotstuff { if (quorum_met){ - high_qc.quorum_met = true; + // "The caller does not need this updated on their high_qc structure -- g" + //high_qc.quorum_met = true; //ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); _high_qc = high_qc; + _high_qc.quorum_met = true; _b_leaf = _high_qc.proposal_id; //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } + + return quorum_met; } } + + return false; } void qc_chain::leader_rotation_check(){ @@ -672,7 +691,7 @@ namespace eosio { namespace hotstuff { } //safenode predicate - bool qc_chain::is_node_safe(hs_proposal_message proposal){ + bool qc_chain::is_node_safe(const hs_proposal_message & proposal){ //ilog(" === is_node_safe ==="); @@ -764,7 +783,7 @@ namespace eosio { namespace hotstuff { } //on proposal received, called from network thread - void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ + void qc_chain::on_hs_proposal_msg(const hs_proposal_message & msg){ std::exception_ptr eptr; try{ //ilog(" === ${id} qc on_hs_proposal_msg ===", ("id", _id)); @@ -780,7 +799,7 @@ namespace eosio { namespace hotstuff { } //on vote received, called from network thread - void qc_chain::on_hs_vote_msg(hs_vote_message msg){ + void qc_chain::on_hs_vote_msg(const hs_vote_message & msg){ std::exception_ptr eptr; try{ //ilog(" === ${id} qc on_hs_vote_msg ===", ("id", _id)); @@ -796,7 +815,7 @@ namespace eosio { namespace hotstuff { } //on new view received, called from network thread - void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ + void qc_chain::on_hs_new_view_msg(const hs_new_view_message & msg){ std::exception_ptr eptr; try{ //ilog(" === ${id} qc on_hs_new_view_msg ===", ("id", _id)); @@ -812,7 +831,7 @@ namespace eosio { namespace hotstuff { } //on new block received, called from network thread - void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ + void qc_chain::on_hs_new_block_msg(const hs_new_block_message & msg){ std::exception_ptr eptr; try{ //ilog(" === ${id} qc on_hs_new_block_msg ===", ("id", _id)); @@ -827,7 +846,7 @@ namespace eosio { namespace hotstuff { handle_eptr(eptr); } - void qc_chain::update(hs_proposal_message proposal){ + void qc_chain::update(const hs_proposal_message & proposal){ //ilog(" === update internal state ==="); //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ @@ -951,7 +970,7 @@ namespace eosio { namespace hotstuff { } } - void qc_chain::commit(hs_proposal_message proposal){ + void qc_chain::commit(const hs_proposal_message & proposal){ /* ilog(" === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", ("block_num", proposal.block_num()) diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test_pacemaker.cpp index 7e82f2e008..9abe22a7d3 100644 --- a/libraries/hotstuff/test_pacemaker.cpp +++ b/libraries/hotstuff/test_pacemaker.cpp @@ -200,25 +200,25 @@ namespace eosio { namespace hotstuff { } }; - void test_pacemaker::send_hs_proposal_msg(name id, hs_proposal_message msg){ + void test_pacemaker::send_hs_proposal_msg(name id, const hs_proposal_message & msg){ //ilog("queuing hs_proposal_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_vote_msg(name id, hs_vote_message msg){ + void test_pacemaker::send_hs_vote_msg(name id, const hs_vote_message & msg){ //ilog("queuing hs_vote_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_block_msg(name id, hs_new_block_message msg){ + void test_pacemaker::send_hs_new_block_msg(name id, const hs_new_block_message & msg){ _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_view_msg(name id, hs_new_view_message msg){ + void test_pacemaker::send_hs_new_view_msg(name id, const hs_new_view_message & msg){ _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::on_hs_proposal_msg(name id, hs_proposal_message msg){ + void test_pacemaker::on_hs_proposal_msg(name id, const hs_proposal_message & msg){ //ilog(" === on_hs_proposal_msg"); auto qc_itr = _qcc_store.begin(); while (qc_itr!=_qcc_store.end()){ @@ -234,7 +234,7 @@ namespace eosio { namespace hotstuff { //ilog(" === end on_hs_proposal_msg"); } - void test_pacemaker::on_hs_vote_msg(name id, hs_vote_message msg){ + void test_pacemaker::on_hs_vote_msg(name id, const hs_vote_message & msg){ //ilog(" === on_hs_vote_msg"); auto qc_itr = _qcc_store.begin(); while (qc_itr!=_qcc_store.end()){ @@ -250,7 +250,7 @@ namespace eosio { namespace hotstuff { //ilog(" === end on_hs_vote_msg"); } - void test_pacemaker::on_hs_new_block_msg(name id, hs_new_block_message msg){ + void test_pacemaker::on_hs_new_block_msg(name id, const hs_new_block_message & msg){ //ilog(" === on_hs_new_block_msg"); auto qc_itr = _qcc_store.begin(); while (qc_itr!=_qcc_store.end()){ @@ -266,7 +266,7 @@ namespace eosio { namespace hotstuff { //ilog(" === end on_hs_new_block_msg"); } - void test_pacemaker::on_hs_new_view_msg(name id, hs_new_view_message msg){ + void test_pacemaker::on_hs_new_view_msg(name id, const hs_new_view_message & msg){ //ilog(" === on_hs_new_view_msg"); auto qc_itr = _qcc_store.begin(); while (qc_itr!=_qcc_store.end()){ diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index c645209950..8500b93aa9 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -143,12 +143,12 @@ namespace eosio { notice_message, request_message, sync_request_message, - signed_block, // which = 7 - packed_transaction, // which = 8 - hs_vote_message, // hotstuff vote message, which = 9 - hs_proposal_message, // hotstuff proposal message, which = 10 - hs_new_view_message, // hotstuff proposal message, which = 11 - hs_new_block_message>; // hotstuff new block message, which = 12 + signed_block, + packed_transaction, + hs_vote_message, + hs_proposal_message, + hs_new_view_message, + hs_new_block_message>; } // namespace eosio diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 8c5633ef4a..e2cdffa803 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -450,9 +450,10 @@ namespace eosio { constexpr uint16_t proto_dup_goaway_resolution = 5; // eosio 2.1: support peer address based duplicate connection resolution constexpr uint16_t proto_dup_node_id_goaway = 6; // eosio 2.1: support peer node_id based duplicate connection resolution constexpr uint16_t proto_leap_initial = 7; // leap client, needed because none of the 2.1 versions are supported + constexpr uint16_t proto_instant_finality = 8; // instant finality #pragma GCC diagnostic pop - constexpr uint16_t net_version_max = proto_leap_initial; + constexpr uint16_t net_version_max = proto_instant_finality; /** * Index by start_block_num @@ -2200,7 +2201,8 @@ namespace eosio { for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; cp->strand.post( [this, cp, msg_val]() { - cp->enqueue( msg_val ); + if (cp->protocol_version >= proto_instant_finality) + cp->enqueue( msg_val ); }); return true; } ); @@ -2212,7 +2214,8 @@ namespace eosio { for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; cp->strand.post( [this, cp, msg_val]() { - cp->enqueue( msg_val ); + if (cp->protocol_version >= proto_instant_finality) + cp->enqueue( msg_val ); }); return true; } ); @@ -2224,7 +2227,8 @@ namespace eosio { for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; cp->strand.post( [this, cp, msg_val]() { - cp->enqueue( msg_val ); + if (cp->protocol_version >= proto_instant_finality) + cp->enqueue( msg_val ); }); return true; } ); @@ -2236,7 +2240,8 @@ namespace eosio { for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; cp->strand.post( [this, cp, msg_val]() { - cp->enqueue( msg_val ); + if (cp->protocol_version >= proto_instant_finality) + cp->enqueue( msg_val ); }); return true; } ); From a5f632fd2fd6981564740c31b0d4e93cf20521ab Mon Sep 17 00:00:00 2001 From: fcecin Date: Sat, 29 Apr 2023 14:05:03 -0300 Subject: [PATCH 024/151] Hotstuff refactor batch 1 - Fixed qc_chain end() iterator dereferencing and raising exceptions when some internal inconsistence in the hotstuff core is detected - Fixed test_hotstuff failing under random conditions (e.g. use of std::vector::reserve()) - Added two alternative implementations to the qc_chain proposal store to help debug potential invalid memory access problems (choose which one to use with a #define); they show similar performance in initial benchmarks, and both seem to be working without issues; we will choose one prior to release - Added missing variable/member initializations - chain_pacemaker now owns and manages its qc_chain object - Removed init() idiom and replaced with full initialization on object construction - Refactored and simplified Pacemaker interfaces (base_pacemaker is the minimal interface that qc_chain needs, only) - Removed exception filters in the hotstuff core (now exceptions will cause tests, and nodeos, to fail) - Lots of miscellaneous simplifications and other improvements to the code --- .../chain/include/eosio/chain/hotstuff.hpp | 24 +- libraries/hotstuff/chain_pacemaker.cpp | 46 +- .../include/eosio/hotstuff/base_pacemaker.hpp | 31 +- .../eosio/hotstuff/chain_pacemaker.hpp | 34 +- .../include/eosio/hotstuff/qc_chain.hpp | 94 +-- .../include/eosio/hotstuff/test_pacemaker.hpp | 61 +- libraries/hotstuff/qc_chain.cpp | 699 ++++++++++-------- libraries/hotstuff/test/test_hotstuff.cpp | 417 ++++++----- libraries/hotstuff/test_pacemaker.cpp | 266 +++---- plugins/producer_plugin/producer_plugin.cpp | 28 +- 10 files changed, 825 insertions(+), 875 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 6e99026037..216d0e5c72 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -12,24 +12,28 @@ namespace eosio { namespace chain { const block_id_type NULL_BLOCK_ID = block_id_type("00"); const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - static uint32_t compute_block_num(block_id_type block_id){ + static uint32_t compute_block_num(block_id_type block_id) { return fc::endian_reverse_u32(block_id._hash[0]); } - static uint64_t compute_height(uint32_t block_height, uint32_t phase_counter){ + static uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) { return (uint64_t{block_height} << 32) | phase_counter; } struct extended_schedule { - producer_authority_schedule producer_schedule; - std::map bls_pub_keys; + producer_authority_schedule producer_schedule; + std::map bls_pub_keys; + + extended_schedule() = default; }; struct quorum_certificate { fc::sha256 proposal_id = NULL_PROPOSAL_ID; - fc::unsigned_int active_finalizers; //bitset encoding, following canonical order + fc::unsigned_int active_finalizers = 0; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; bool quorum_met = false; + + quorum_certificate() = default; }; struct hs_vote_message { @@ -50,13 +54,8 @@ namespace eosio { namespace chain { hs_proposal_message() = default; - uint32_t block_num()const { - return compute_block_num(block_id); - } - - uint64_t get_height()const { - return compute_height(compute_block_num(block_id), phase_counter); - }; + uint32_t block_num() const { return compute_block_num(block_id); } + uint64_t get_height() const { return compute_height(compute_block_num(block_id), phase_counter); }; }; struct hs_new_block_message { @@ -72,7 +71,6 @@ namespace eosio { namespace chain { using hs_proposal_message_ptr = std::shared_ptr; using hs_vote_message_ptr = std::shared_ptr; - using hs_new_view_message_ptr = std::shared_ptr; using hs_new_block_message_ptr = std::shared_ptr; diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 98c73d7d35..b9debdfcbe 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -100,8 +100,10 @@ namespace eosio { namespace hotstuff { #endif //=============================================================================================== - void chain_pacemaker::init(controller* chain){ - _chain = chain; + chain_pacemaker::chain_pacemaker(controller* chain, std::set my_producers, bool info_logging, bool error_logging) + : _chain(chain), + _qc_chain("default"_n, this, my_producers, info_logging, error_logging) + { } name chain_pacemaker::get_proposer(){ @@ -143,65 +145,61 @@ namespace eosio { namespace hotstuff { void chain_pacemaker::beat(){ csc prof("beat"); - std::lock_guard g( this-> _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_state_mutex ); prof.core_in(); - _qc_chain->on_beat(); + _qc_chain.on_beat(); prof.core_out(); } - void chain_pacemaker::assign_qc_chain(name name, qc_chain& qcc){ - _qc_chain = &qcc; - } - - void chain_pacemaker::send_hs_proposal_msg(name id, const hs_proposal_message & msg){ + void chain_pacemaker::send_hs_proposal_msg(const hs_proposal_message & msg, name id){ hs_proposal_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_proposal_msg(msg_ptr); } - void chain_pacemaker::send_hs_vote_msg(name id, const hs_vote_message & msg){ + void chain_pacemaker::send_hs_vote_msg(const hs_vote_message & msg, name id){ hs_vote_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_vote_msg(msg_ptr); } - void chain_pacemaker::send_hs_new_block_msg(name id, const hs_new_block_message & msg){ + void chain_pacemaker::send_hs_new_block_msg(const hs_new_block_message & msg, name id){ hs_new_block_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_new_block_msg(msg_ptr); } - void chain_pacemaker::send_hs_new_view_msg(name id, const hs_new_view_message & msg){ + void chain_pacemaker::send_hs_new_view_msg(const hs_new_view_message & msg, name id){ hs_new_view_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_new_view_msg(msg_ptr); } - void chain_pacemaker::on_hs_proposal_msg(name id, const hs_proposal_message & msg){ + void chain_pacemaker::on_hs_proposal_msg(const hs_proposal_message & msg){ csc prof("prop"); - std::lock_guard g( this-> _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_state_mutex ); prof.core_in(); - _qc_chain->on_hs_proposal_msg(msg); + _qc_chain.on_hs_proposal_msg(msg); prof.core_out(); } - void chain_pacemaker::on_hs_vote_msg(name id, const hs_vote_message & msg){ + void chain_pacemaker::on_hs_vote_msg(const hs_vote_message & msg){ csc prof("vote"); - std::lock_guard g( this-> _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_state_mutex ); prof.core_in(); - _qc_chain->on_hs_vote_msg(msg); + _qc_chain.on_hs_vote_msg(msg); prof.core_out(); } - void chain_pacemaker::on_hs_new_block_msg(name id, const hs_new_block_message & msg){ + void chain_pacemaker::on_hs_new_block_msg(const hs_new_block_message & msg){ csc prof("nblk"); - std::lock_guard g( this-> _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_state_mutex ); prof.core_in(); - _qc_chain->on_hs_new_block_msg(msg); + _qc_chain.on_hs_new_block_msg(msg); prof.core_out(); } - void chain_pacemaker::on_hs_new_view_msg(name id, const hs_new_view_message & msg){ + void chain_pacemaker::on_hs_new_view_msg(const hs_new_view_message & msg){ csc prof("view"); - std::lock_guard g( this-> _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_state_mutex ); prof.core_in(); - _qc_chain->on_hs_new_view_msg(msg); + _qc_chain.on_hs_new_view_msg(msg); prof.core_out(); } diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index a095dc3dc6..3caf0c7709 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -12,10 +12,15 @@ namespace eosio { namespace hotstuff { class qc_chain; + // Abstract pacemaker; a reference of this type will only be used by qc_chain, as qc_chain + // cannot know which environment it is in. + // All other pacemaker clients will be interacting with a reference to the concrete class: + // - Testers will access a test_pacemaker reference; + // - Real-world code will access a chain_pacemaker reference. class base_pacemaker { public: - //todo : discuss + //TODO: discuss virtual uint32_t get_quorum_threshold() = 0; virtual block_id_type get_current_block_id() = 0; @@ -26,25 +31,11 @@ namespace eosio { namespace hotstuff { virtual name get_next_leader() = 0; virtual std::vector get_finalizers() = 0; - //block / proposal API - virtual void beat() = 0; - - //todo : abstract further - - //qc_chain event subscription - virtual void assign_qc_chain(name name, qc_chain& qcc) = 0; - - //outbound communications - virtual void send_hs_proposal_msg(name id, const hs_proposal_message & msg) = 0; - virtual void send_hs_vote_msg(name id, const hs_vote_message & msg) = 0; - virtual void send_hs_new_block_msg(name id, const hs_new_block_message & msg) = 0; - virtual void send_hs_new_view_msg(name id, const hs_new_view_message & msg) = 0; - - //inbound communications - virtual void on_hs_vote_msg(name id, const hs_vote_message & msg) = 0; //confirmation msg event handler - virtual void on_hs_proposal_msg(name id, const hs_proposal_message & msg) = 0; //consensus msg event handler - virtual void on_hs_new_view_msg(name id, const hs_new_view_message & msg) = 0; //new view msg event handler - virtual void on_hs_new_block_msg(name id, const hs_new_block_message & msg) = 0; //new block msg event handler + //outbound communications; 'id' is the producer name (can be ignored if/when irrelevant to the implementer) + virtual void send_hs_proposal_msg(const hs_proposal_message & msg, name id) = 0; + virtual void send_hs_vote_msg(const hs_vote_message & msg, name id) = 0; + virtual void send_hs_new_view_msg(const hs_new_view_message & msg, name id) = 0; + virtual void send_hs_new_block_msg(const hs_new_block_message & msg, name id) = 0; }; }} diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index 2e905a687f..b7f8e32e6c 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -11,9 +11,14 @@ namespace eosio { namespace hotstuff { //class-specific functions - void init(controller* chain); + chain_pacemaker(controller* chain, std::set my_producers, bool info_logging, bool error_logging); - std::mutex _hotstuff_state_mutex; + void beat(); + + 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 + void on_hs_new_view_msg(const hs_new_view_message & msg); //new view msg event handler + void on_hs_new_block_msg(const hs_new_block_message & msg); //new block msg event handler //base_pacemaker interface functions @@ -26,27 +31,20 @@ namespace eosio { namespace hotstuff { uint32_t get_quorum_threshold(); - void assign_qc_chain(name name, qc_chain& qcc); - - void beat(); - - void send_hs_proposal_msg(name id, const hs_proposal_message & msg); - void send_hs_vote_msg(name id, const hs_vote_message & msg); - void send_hs_new_block_msg(name id, const hs_new_block_message & msg); - void send_hs_new_view_msg(name id, const hs_new_view_message & msg); - - void on_hs_vote_msg(name id, const hs_vote_message & msg); //confirmation msg event handler - void on_hs_proposal_msg(name id, const hs_proposal_message & msg); //consensus msg event handler - void on_hs_new_view_msg(name id, const hs_new_view_message & msg); //new view msg event handler - void on_hs_new_block_msg(name id, const hs_new_block_message & msg); //new block msg event handler + void send_hs_proposal_msg(const hs_proposal_message & msg, name id); + void send_hs_vote_msg(const hs_vote_message & msg, name id); + void send_hs_new_view_msg(const hs_new_view_message & msg, name id); + void send_hs_new_block_msg(const hs_new_block_message & msg, name id); private: - chain::controller* _chain = nullptr; + std::mutex _hotstuff_state_mutex; + + chain::controller* _chain = nullptr; - qc_chain* _qc_chain = nullptr; + qc_chain _qc_chain; - uint32_t _quorum_threshold = 15; //todo : calculate from schedule + uint32_t _quorum_threshold = 15; //FIXME/TODO: calculate from schedule }; }} diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 9d9580e212..d575c42443 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -22,6 +22,9 @@ #include +// Enable this to swap the multi-index proposal store with std::map +//#define QC_CHAIN_SIMPLE_PROPOSAL_STORE + namespace eosio { namespace hotstuff { using boost::multi_index_container; @@ -29,21 +32,12 @@ namespace eosio { namespace hotstuff { using namespace eosio::chain; - //const uint32_t INTERUPT_TIMEOUT = 6; //sufficient timeout for new leader to be selected - class qc_chain { public: - static void handle_eptr(std::exception_ptr eptr){ - try { - if (eptr) { - std::rethrow_exception(eptr); - } - } catch(const std::exception& e) { - ilog("Caught exception ${ex}" , ("ex", e.what())); - std::exit(0); - } - }; + qc_chain() = delete; + + qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, bool info_logging, bool error_logging); //todo : remove. bls12-381 key used for testing purposes std::vector _seed = @@ -60,7 +54,7 @@ namespace eosio { namespace hotstuff { vote = 4 }; - bool _chained_mode = false ; + bool _chained_mode = false; fc::sha256 _b_leaf = NULL_PROPOSAL_ID; fc::sha256 _b_lock = NULL_PROPOSAL_ID; @@ -72,38 +66,27 @@ namespace eosio { namespace hotstuff { block_id_type _pending_proposal_block = NULL_BLOCK_ID; - uint32_t _v_height; - - bool _log = true; - bool _errors = true; + uint32_t _v_height = 0; eosio::chain::quorum_certificate _high_qc; eosio::chain::quorum_certificate _current_qc; eosio::chain::extended_schedule _schedule; - std::set _my_producers; - name _id; - struct by_proposal_id{}; - struct by_proposal_height{}; + base_pacemaker* _pacemaker = nullptr; - typedef multi_index_container< - hs_proposal_message, - indexed_by< - hashed_unique< - tag, - BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) - >, - ordered_non_unique< - tag, - BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) - > - > - > proposal_store_type; + std::set _my_producers; - proposal_store_type _proposal_store; //internal proposals store + bool _log = true; + bool _errors = true; + + // returns nullptr if not found + const hs_proposal_message* get_proposal(fc::sha256 proposal_id); + + // returns false if proposal with that same ID already exists at the store of its height + bool insert_proposal(const hs_proposal_message & proposal); uint32_t positive_bits_count(fc::unsigned_int value); @@ -115,10 +98,6 @@ namespace eosio { namespace hotstuff { bool evaluate_quorum(const extended_schedule & es, fc::unsigned_int finalizers, const fc::crypto::blslib::bls_signature & agg_sig, const hs_proposal_message & proposal); //evaluate quorum for a proposal -/* name get_proposer(); - name get_leader(); - name get_incoming_leader(); //get incoming leader*/ - // qc.quorum_met has to be updated by the caller (if it wants to) based on the return value of this method bool is_quorum_met(const eosio::chain::quorum_certificate & qc, const extended_schedule & schedule, const hs_proposal_message & proposal); //check if quorum has been met over a proposal @@ -127,8 +106,6 @@ namespace eosio { namespace hotstuff { hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); //create new proposal message hs_new_block_message new_block_candidate(block_id_type block_id); //create new block message - void init(name id, base_pacemaker& pacemaker, std::set my_producers, bool info_logging, bool error_logging); //initialize qc object and add reference to the pacemaker - bool am_i_proposer(); //check if I am the current proposer bool am_i_leader(); //check if I am the current leader bool am_i_finalizer(); //check if I am one of the current finalizers @@ -168,13 +145,38 @@ namespace eosio { namespace hotstuff { void gc_proposals(uint64_t cutoff); //garbage collection of old proposals - qc_chain(){ - //ilog("_high_qc : ${qc_id}", ("qc_id", _high_qc.proposal_id)); - }; +private: - private: +#ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE + // keep one proposal store (id -> proposal) by each height (height -> proposal store) + typedef map proposal_store; + typedef map::iterator ps_iterator; + typedef map::iterator ps_height_iterator; + map _proposal_stores_by_height; - base_pacemaker* _pacemaker = nullptr; + // get the height of a given proposal id + typedef map::iterator ph_iterator; + map _proposal_height; +#else + struct by_proposal_id{}; + struct by_proposal_height{}; + + typedef multi_index_container< + hs_proposal_message, + indexed_by< + hashed_unique< + tag, + BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) + >, + ordered_non_unique< + tag, + BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) + > + > + > proposal_store_type; + + proposal_store_type _proposal_store; //internal proposals store +#endif }; }} /// eosio::qc_chain diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index 04fa265942..1b60e171f0 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -9,36 +9,10 @@ namespace eosio { namespace hotstuff { //class-specific functions - struct indexed_qc_chain { - name _name; - bool _active = true; - qc_chain* _qc_chain = nullptr; - - uint64_t by_name() const { return _name.to_uint64_t(); }; - - indexed_qc_chain(const name & name, qc_chain* qc_chain, bool active = true) - : _name(name), _active(active), _qc_chain(qc_chain) { } - indexed_qc_chain() = delete; - }; - - struct by_name_id{}; - - typedef multi_index_container< - indexed_qc_chain, - indexed_by< - ordered_unique< - tag, - BOOST_MULTI_INDEX_CONST_MEM_FUN(indexed_qc_chain, uint64_t, by_name) - > - > - > qc_chain_type; - - qc_chain_type _qcc_store; + bool is_qc_chain_active(const name & qcc_name) { return _qcc_deactivated.find(qcc_name) == _qcc_deactivated.end(); } using hotstuff_message = std::pair>; - //void init(std::vector unique_replicas); - void set_proposer(name proposer); void set_leader(name leader); @@ -55,8 +29,6 @@ namespace eosio { namespace hotstuff { void pipe(std::vector messages); - // Remove unused return value - //std::vector void dispatch(std::string memo, int count); std::vector dispatch(std::string memo); @@ -64,7 +36,15 @@ namespace eosio { namespace hotstuff { void activate(name replica); void deactivate(name replica); - //indexed_qc_chain get_qc_chain(name replica); + // must be called to register every qc_chain object created by the testcase + void register_qc_chain(name name, std::shared_ptr qcc_ptr); + + void beat(); + + void on_hs_vote_msg(const hs_vote_message & msg, name id); //confirmation msg event handler + void on_hs_proposal_msg(const hs_proposal_message & msg, name id); //consensus msg event handler + void on_hs_new_view_msg(const hs_new_view_message & msg, name id); //new view msg event handler + void on_hs_new_block_msg(const hs_new_block_message & msg, name id); //new block msg event handler //base_pacemaker interface functions @@ -77,21 +57,18 @@ namespace eosio { namespace hotstuff { uint32_t get_quorum_threshold(); - void assign_qc_chain(name name, qc_chain& qcc); - - void beat(); + void send_hs_proposal_msg(const hs_proposal_message & msg, name id); + void send_hs_vote_msg(const hs_vote_message & msg, name id); + void send_hs_new_block_msg(const hs_new_block_message & msg, name id); + void send_hs_new_view_msg(const hs_new_view_message & msg, name id); - void send_hs_proposal_msg(name id, const hs_proposal_message & msg); - void send_hs_vote_msg(name id, const hs_vote_message & msg); - void send_hs_new_block_msg(name id, const hs_new_block_message & msg); - void send_hs_new_view_msg(name id, const hs_new_view_message & msg); + std::vector _pending_message_queue; - void on_hs_vote_msg(name id, const hs_vote_message & msg); //confirmation msg event handler - void on_hs_proposal_msg(name id, const hs_proposal_message & msg); //consensus msg event handler - void on_hs_new_view_msg(name id, const hs_new_view_message & msg); //new view msg event handler - void on_hs_new_block_msg(name id, const hs_new_block_message & msg); //new block msg event handler + // qc_chain id to qc_chain object + map> _qcc_store; - std::vector _pending_message_queue; + // qc_chain ids in this set are currently deactivated + set _qcc_deactivated; private: diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index bec32bdbca..67e0e2d3b5 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -43,6 +43,55 @@ namespace eosio { namespace hotstuff { + const hs_proposal_message* qc_chain::get_proposal(fc::sha256 proposal_id) { +#ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE + if (proposal_id == NULL_PROPOSAL_ID) + return nullptr; + ph_iterator h_it = _proposal_height.find( proposal_id ); + if (h_it == _proposal_height.end()) + return nullptr; + uint64_t proposal_height = h_it->second; + ps_height_iterator psh_it = _proposal_stores_by_height.find( proposal_height ); + if (psh_it == _proposal_stores_by_height.end()) + return nullptr; + proposal_store & pstore = psh_it->second; + ps_iterator ps_it = pstore.find( proposal_id ); + if (ps_it == pstore.end()) + return nullptr; + const hs_proposal_message & proposal = ps_it->second; + return &proposal; +#else + proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find( proposal_id ); + if (itr == _proposal_store.get().end()) + return nullptr; + return &(*itr); +#endif + } + + bool qc_chain::insert_proposal(const hs_proposal_message & proposal) { +#ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE + uint64_t proposal_height = proposal.get_height(); + ps_height_iterator psh_it = _proposal_stores_by_height.find( proposal_height ); + if (psh_it == _proposal_stores_by_height.end()) { + _proposal_stores_by_height.emplace( proposal_height, proposal_store() ); + psh_it = _proposal_stores_by_height.find( proposal_height ); + } + proposal_store & pstore = psh_it->second; + const fc::sha256 & proposal_id = proposal.proposal_id; + ps_iterator ps_it = pstore.find( proposal_id ); + if (ps_it != pstore.end()) + return false; // duplicate proposal insertion, so don't change anything actually + _proposal_height.emplace( proposal_id, proposal_height ); + pstore.emplace( proposal_id, proposal ); + return true; +#else + if (get_proposal( proposal.proposal_id ) != nullptr) + return false; + _proposal_store.insert(proposal); //new proposal + return true; +#endif + } + uint32_t qc_chain::positive_bits_count(fc::unsigned_int value){ boost::dynamic_bitset b(21, value); uint32_t count = 0; @@ -52,29 +101,29 @@ namespace eosio { namespace hotstuff { return count; } - fc::unsigned_int qc_chain::update_bitset(fc::unsigned_int value, name finalizer){ - /*ilog(" === update bitset ${value} ${finalizer}", - ("value", value) - ("finalizer", finalizer));*/ + fc::unsigned_int qc_chain::update_bitset(fc::unsigned_int value, name finalizer ) { + //ilog(" === update bitset ${value} ${finalizer}", + // ("value", value) + // ("finalizer", finalizer)); boost::dynamic_bitset b( 21, value ); vector finalizers = _pacemaker->get_finalizers(); - for (size_t i = 0; i < finalizers.size();i++){ - if (finalizers[i] == finalizer){ + for (size_t i = 0; i < finalizers.size();i++) { + if (finalizers[i] == finalizer) { b.flip(i); - /*ilog(" === finalizer found ${finalizer} new value : ${value}", - ("finalizer", finalizer) - ("value", b.to_ulong()));*/ + //ilog(" === finalizer found ${finalizer} new value : ${value}", + // ("finalizer", finalizer) + // ("value", b.to_ulong())); return b.to_ulong(); } } - /*ilog(" *** finalizer not found ${finalizer}", - ("finalizer", finalizer));*/ + //ilog(" *** finalizer not found ${finalizer}", + // ("finalizer", finalizer)); - throw std::runtime_error("finalizer not found"); + throw std::runtime_error("qc_chain internal error: finalizer not found"); } digest_type qc_chain::get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ @@ -83,17 +132,20 @@ namespace eosio { namespace hotstuff { return h2; } - std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ + std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id) { std::vector ret_arr; - proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); - b_2_itr = _proposal_store.get().find( proposal_id ); - if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); - if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); - if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); - if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); - if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); + const hs_proposal_message *b, *b1, *b2; + b2 = get_proposal( proposal_id ); + if (b2 != nullptr) { + ret_arr.push_back( *b2 ); + b1 = get_proposal( b2->justify.proposal_id ); + if (b1 != nullptr) { + ret_arr.push_back( *b1 ); + b = get_proposal( b1->justify.proposal_id ); + if (b != nullptr) + ret_arr.push_back( *b ); + } + } return ret_arr; } @@ -113,22 +165,27 @@ namespace eosio { namespace hotstuff { hs_proposal_message b1 = *itr; if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; else { - proposal_store_type::nth_index<0>::type::iterator p_itr; - p_itr = _proposal_store.get().find( b1.parent_id ); - b_new.final_on_qc = p_itr->final_on_qc; + const hs_proposal_message *p = get_proposal( b1.parent_id ); + //EOS_ASSERT( p != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", b1.parent_id) ); + if (p != nullptr) { + b_new.final_on_qc = p->final_on_qc; + } else { + if (_errors) ilog(" *** ${id} expected to find proposal in new_proposal_candidate() but not found : ${proposal_id}", ("id",_id)("proposal_id", b1.parent_id)); + } } } } b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); - if (_log) ilog(" === ${id} creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", - ("id", _id) - ("block_num", b_new.block_num()) - ("phase_counter", b_new.phase_counter) - ("proposal_id", b_new.proposal_id) - ("parent_id", b_new.parent_id) - ("justify", b_new.justify.proposal_id)); + if (_log) + ilog(" === ${id} creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + ("id", _id) + ("block_num", b_new.block_num()) + ("phase_counter", b_new.phase_counter) + ("proposal_id", b_new.proposal_id) + ("parent_id", b_new.parent_id) + ("justify", b_new.justify.proposal_id)); return b_new; } @@ -171,7 +228,7 @@ namespace eosio { namespace hotstuff { } // **************************************************************************************************** - // FIXME/TODO/REVIEW: I removed this since it doesn't seem to be doing anything at the moment + // FIXME/TODO: I removed this since it doesn't seem to be doing anything at the moment // **************************************************************************************************** // //fc::crypto::blslib::bls_signature justification_agg_sig; @@ -195,28 +252,21 @@ namespace eosio { namespace hotstuff { else { //ilog(" === qc : ${qc}", ("qc", qc)); - // Caller has to update the quorum_met flag on its qc object based on the return value of this method -- fcecin - // - //bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); - //qc.quorum_met = quorum_met; - //return qc.quorum_met; - // + // If the caller wants to update the quorum_met flag on its "qc" object, it will have to do so + // based on the return value of this method, since "qc" here is const. return evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); } } - void qc_chain::init(name id, base_pacemaker& pacemaker, std::set my_producers, bool info_logging, bool error_logging){ - - _id = id; - _log = info_logging; - _errors = error_logging; - _pacemaker = &pacemaker; - _my_producers = my_producers; - _pacemaker->assign_qc_chain(id, *this); + qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, bool info_logging, bool error_logging) + : _id(id), + _pacemaker(pacemaker), + _my_producers(my_producers), + _log(info_logging), + _errors(error_logging) + { if (_log) ilog(" === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); - - //ilog(" === name ${name}", ("name", *itr)); } bool qc_chain::am_i_proposer(){ @@ -253,7 +303,7 @@ namespace eosio { namespace hotstuff { std::vector h = std::vector(digest.data(), digest.data() + 32); - fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer + fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //FIXME/TODO: use appropriate private key for each producer hs_vote_message v_msg = {proposal.proposal_id, finalizer, sig}; return v_msg; @@ -265,26 +315,24 @@ namespace eosio { namespace hotstuff { if (proposal.justify.proposal_id != NULL_PROPOSAL_ID){ - auto jp_itr = _proposal_store.get().find( proposal.justify.proposal_id ); - - if (jp_itr == _proposal_store.get().end()) { + const hs_proposal_message *jp = get_proposal( proposal.justify.proposal_id ); + if (jp == nullptr) { if (_errors) ilog(" *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); return; //can't recognize a proposal with an unknown justification } } - auto pid_itr = _proposal_store.get().find( proposal.proposal_id ); - - if (pid_itr != _proposal_store.get().end()) { + const hs_proposal_message *p = get_proposal( proposal.proposal_id ); + if (p != nullptr) { if (_errors) ilog(" *** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); - if (pid_itr->justify.proposal_id != proposal.justify.proposal_id) { + if (p->justify.proposal_id != proposal.justify.proposal_id) { if (_errors) ilog(" *** ${id} two identical proposals (${proposal_id}) have different justifications : ${justify_1} vs ${justify_2}", ("id",_id) ("proposal_id", proposal.proposal_id) - ("justify_1", pid_itr->justify.proposal_id) + ("justify_1", p->justify.proposal_id) ("justify_2", proposal.justify.proposal_id)); } @@ -292,22 +340,41 @@ namespace eosio { namespace hotstuff { return; //already aware of proposal, nothing to do } +#ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE + ps_height_iterator psh_it = _proposal_stores_by_height.find( proposal.get_height() ); + if (psh_it != _proposal_stores_by_height.end()) + { + proposal_store & pstore = psh_it->second; + ps_iterator ps_it = pstore.begin(); + while (ps_it != pstore.end()) + { + hs_proposal_message & existing_proposal = ps_it->second; +#else + //height is not necessarily unique, so we iterate over all prior proposals at this height auto hgt_itr = _proposal_store.get().lower_bound( proposal.get_height() ); auto end_itr = _proposal_store.get().upper_bound( proposal.get_height() ); + while (hgt_itr != end_itr) + { + const hs_proposal_message & existing_proposal = *hgt_itr; +#endif - //height is not necessarily unique, so we iterate over all prior proposals at this height - while (hgt_itr != end_itr) { if (_errors) ilog(" *** ${id} received a different proposal at the same height (${block_num}, ${phase_counter})", ("id",_id) - ("block_num", hgt_itr->block_num()) - ("phase_counter", hgt_itr->phase_counter)); + ("block_num", existing_proposal.block_num()) + ("phase_counter", existing_proposal.phase_counter)); if (_errors) ilog(" *** Proposal #1 : ${proposal_id_1} Proposal #2 : ${proposal_id_2}", - ("proposal_id_1", hgt_itr->proposal_id) + ("proposal_id_1", existing_proposal.proposal_id) ("proposal_id_2", proposal.proposal_id)); +#ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE + ++ps_it; + } + } +#else hgt_itr++; } +#endif if (_log) ilog(" === ${id} received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", ("id", _id) @@ -317,7 +384,8 @@ namespace eosio { namespace hotstuff { ("parent_id", proposal.parent_id) ("justify", proposal.justify.proposal_id)); - _proposal_store.insert(proposal); //new proposal + bool success = insert_proposal( proposal ); + EOS_ASSERT( success , chain_exception, "internal error: duplicate proposal insert attempt" ); // can't happen unless bad mutex somewhere; already checked for this //if I am a finalizer for this proposal and the safenode predicate for a possible vote is true, sign bool am_finalizer = am_i_finalizer(); @@ -341,11 +409,11 @@ namespace eosio { namespace hotstuff { hs_vote_message v_msg = sign_proposal(proposal, *prod_itr); -/* if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id));*/ + //if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + // ("id", _id) + // ("block_num", proposal.block_num()) + // ("phase_counter", proposal.phase_counter) + // ("proposal_id", proposal.proposal_id)); //send_hs_vote_msg(v_msg); msgs.push_back(v_msg); @@ -355,17 +423,17 @@ namespace eosio { namespace hotstuff { mf_itr++; } } -/* else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id));*/ + //else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + // ("id", _id) + // ("block_num", proposal.block_num()) + // ("phase_counter", proposal.phase_counter) + // ("proposal_id", proposal.proposal_id)); //update internal state update(proposal); - for (auto &msg : msgs){ + for (auto &msg : msgs) { send_hs_vote_msg(msg); } @@ -380,21 +448,21 @@ namespace eosio { namespace hotstuff { //auto start = fc::time_point::now(); - //todo : check for duplicate or invalid vote. We will return in either case, but keep proposals for evidence of double signing + //TODO: check for duplicate or invalid vote. We will return in either case, but keep proposals for evidence of double signing - bool am_leader = am_i_leader(); //am I leader? + bool am_leader = am_i_leader(); - if(!am_leader) return; + if (!am_leader) + return; //ilog(" === Process vote from ${finalizer} : current bitset ${value}" , ("finalizer", vote.finalizer)("value", _current_qc.active_finalizers)); - //only leader need to take action on votes - - if (vote.proposal_id != _current_qc.proposal_id) return; - - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); + // only leader need to take action on votes + if (vote.proposal_id != _current_qc.proposal_id) + return; - if (p_itr==_proposal_store.get().end()){ + const hs_proposal_message *p = get_proposal( vote.proposal_id ); + if (p == nullptr) { if (_errors) ilog(" *** ${id} couldn't find proposal", ("id",_id)); if (_errors) ilog(" *** ${id} vote : ${vote}", ("vote", vote)("id",_id)); return; @@ -402,23 +470,25 @@ namespace eosio { namespace hotstuff { bool quorum_met = _current_qc.quorum_met; //check if quorum already met - //if quorum is already met, we don't need to do anything else. Otherwise, we aggregate the signature + // If quorum is already met, we don't need to do anything else. Otherwise, we aggregate the signature. if (!quorum_met){ - if (_current_qc.active_finalizers>0) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); - else _current_qc.active_agg_sig = vote.sig; + if (_current_qc.active_finalizers>0) + _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); + else + _current_qc.active_agg_sig = vote.sig; _current_qc.active_finalizers = update_bitset(_current_qc.active_finalizers, vote.finalizer); - quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); + quorum_met = is_quorum_met(_current_qc, _schedule, *p); if (quorum_met){ _current_qc.quorum_met = true; if (_log) ilog(" === ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", - ("block_num", p_itr->block_num()) - ("phase_counter", p_itr->phase_counter) + ("block_num", p->block_num()) + ("phase_counter", p->phase_counter) ("proposal_id", vote.proposal_id) ("id", _id)); @@ -429,18 +499,21 @@ namespace eosio { namespace hotstuff { leader_rotation_check(); //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet - if (_chained_mode==false && p_itr->phase_counter<3){ + if (_chained_mode == false && p->phase_counter < 3) { //if (_log) ilog(" === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); hs_proposal_message proposal_candidate; - if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); - else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); + if (_pending_proposal_block == NULL_BLOCK_ID) + proposal_candidate = new_proposal_candidate( p->block_id, p->phase_counter + 1 ); + else + proposal_candidate = new_proposal_candidate( _pending_proposal_block, 0 ); reset_qc(proposal_candidate.proposal_id); //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); + _pending_proposal_block = NULL_BLOCK_ID; _b_leaf = proposal_candidate.proposal_id; @@ -468,47 +541,50 @@ namespace eosio { namespace hotstuff { void qc_chain::send_hs_proposal_msg(const hs_proposal_message & msg){ //ilog(" === broadcast_hs_proposal ==="); //hs_proposal_message_ptr ptr = std::make_shared(msg); - _pacemaker->send_hs_proposal_msg(_id, msg); + _pacemaker->send_hs_proposal_msg(msg, _id); process_proposal(msg); } void qc_chain::send_hs_vote_msg(const hs_vote_message & msg){ //ilog(" === broadcast_hs_vote ==="); //hs_vote_message_ptr ptr = std::make_shared(msg); - _pacemaker->send_hs_vote_msg(_id, msg); + _pacemaker->send_hs_vote_msg(msg, _id); process_vote(msg); } void qc_chain::send_hs_new_view_msg(const hs_new_view_message & msg){ //ilog(" === broadcast_hs_new_view ==="); //hs_new_view_message_ptr ptr = std::make_shared(msg); - _pacemaker->send_hs_new_view_msg(_id, msg); + _pacemaker->send_hs_new_view_msg(msg, _id); } void qc_chain::send_hs_new_block_msg(const hs_new_block_message & msg){ //ilog(" === broadcast_hs_new_block ==="); //hs_new_block_message_ptr ptr = std::make_shared(msg); - _pacemaker->send_hs_new_block_msg(_id, msg); + _pacemaker->send_hs_new_block_msg(msg, _id); } //extends predicate bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ - //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified - - proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); + //TODO: confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified uint32_t counter = 0; - - while (itr!=_proposal_store.get().end()){ - itr = _proposal_store.get().find(itr->parent_id ); - if (itr->proposal_id == ancestor){ - if (counter>25) { + const hs_proposal_message *p = get_proposal( descendant ); + while (p != nullptr) { + fc::sha256 parent_id = p->parent_id; + p = get_proposal( parent_id ); + if (p == nullptr) { + if (_errors) ilog(" *** ${id} cannot find proposal id while looking for ancestor : ${proposal_id}", ("id",_id)("proposal_id", parent_id)); + return false; + } + if (p->proposal_id == ancestor) { + if (counter > 25) { if (_errors) ilog(" *** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); } return true; } - counter++; + ++counter; } if (_errors) ilog(" *** ${id} extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", @@ -520,96 +596,82 @@ namespace eosio { namespace hotstuff { } void qc_chain::on_beat(){ - std::exception_ptr eptr; - try{ - //auto start = fc::time_point::now(); - //if (_log) ilog(" === ${id} on beat === ", ("id", _id)); + //auto start = fc::time_point::now(); - //std::lock_guard g( this-> _hotstuff_state_mutex ); + //if (_log) ilog(" === ${id} on beat === ", ("id", _id)); - name current_producer = _pacemaker->get_leader(); + // FIXME/TODO: this hardcoded string name check is probably not exactly what we want here. + name current_producer = _pacemaker->get_leader(); + if (current_producer == "eosio"_n) + return; - if (current_producer == "eosio"_n) return; + block_id_type current_block_id = _pacemaker->get_current_block_id(); - block_id_type current_block_id = _pacemaker->get_current_block_id(); + //ilog(" === qc chain on_beat ${my_producers}", ("my_producers", _my_producers)); - //ilog(" === qc chain on_beat ${my_producers}", ("my_producers", _my_producers)); + bool am_proposer = am_i_proposer(); + bool am_leader = am_i_leader(); - bool am_proposer = am_i_proposer(); + //if (_log) ilog(" === ${id} am_proposer = ${am_proposer}", ("am_proposer", am_proposer)("id", _id)); + //if (_log) ilog(" === ${id} am_leader = ${am_leader}", ("am_leader", am_leader)("id", _id)); - bool am_leader = am_i_leader(); + if (!am_proposer && !am_leader){ + return; //nothing to do + } - //if (_log) ilog(" === ${id} am_proposer = ${am_proposer}", ("am_proposer", am_proposer)("id", _id)); - //if (_log) ilog(" === ${id} am_leader = ${am_leader}", ("am_leader", am_leader)("id", _id)); + //if I am the leader + if (am_leader) { - if (!am_proposer && !am_leader){ - return; //nothing to do + //if I'm not also the proposer, perform block validation as required + if (!am_proposer){ + //TODO: extra validation? } - //if I am the leader - if (am_leader){ + if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false) { - //if I'm not also the proposer, perform block validation as required - if (!am_proposer){ + //if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", + // ("id", _id) + // ("proposal_id", _current_qc.proposal_id) + // ("quorum_met", _current_qc.quorum_met)); + //if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", current_block_id)); - //todo : extra validation? + _pending_proposal_block = current_block_id; - } + } else { - if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ -/* - if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", - ("id", _id) - ("proposal_id", _current_qc.proposal_id) - ("quorum_met", _current_qc.quorum_met)); + //if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", + // ("id", _id) + // ("proposal_id", _current_qc.proposal_id) + // ("quorum_met", _current_qc.quorum_met)); - if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", current_block_id));*/ - _pending_proposal_block = current_block_id; + hs_proposal_message proposal_candidate = new_proposal_candidate(current_block_id, 0 ); - } - else { - -/* if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", - ("id", _id) - ("proposal_id", _current_qc.proposal_id) - ("quorum_met", _current_qc.quorum_met)); -*/ - hs_proposal_message proposal_candidate = new_proposal_candidate(current_block_id, 0 ); - - reset_qc(proposal_candidate.proposal_id); + reset_qc(proposal_candidate.proposal_id); - //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (on_beat)", ("id", _id)); + //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (on_beat)", ("id", _id)); - _pending_proposal_block = NULL_BLOCK_ID; + _pending_proposal_block = NULL_BLOCK_ID; - _b_leaf = proposal_candidate.proposal_id; + _b_leaf = proposal_candidate.proposal_id; - send_hs_proposal_msg(proposal_candidate); + send_hs_proposal_msg(proposal_candidate); - //if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); - } + //if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); } - else { - //if I'm only a proposer and not the leader, I send a new block message + } else { + //if I'm only a proposer and not the leader, I send a new block message + hs_new_block_message block_candidate = new_block_candidate(current_block_id); - hs_new_block_message block_candidate = new_block_candidate(current_block_id); + //ilog(" === broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); - //ilog(" === broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); - - send_hs_new_block_msg(block_candidate); - } - - //auto total_time = fc::time_point::now() - start; - //if (_log) ilog(" ... on_beat() total time : ${total_time}", ("total_time", total_time)); - //ilog(" === end of on_beat"); + send_hs_new_block_msg(block_candidate); } - catch (...){ - ilog("error during on_beat"); - eptr = std::current_exception(); // capture - } - handle_eptr(eptr); + + //auto total_time = fc::time_point::now() - start; + //if (_log) ilog(" ... on_beat() total time : ${total_time}", ("total_time", total_time)); + //ilog(" === end of on_beat"); } bool qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ @@ -626,20 +688,18 @@ namespace eosio { namespace hotstuff { } else { - proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; - proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; + const hs_proposal_message *old_high_qc_prop = get_proposal( _high_qc.proposal_id ); + const hs_proposal_message *new_high_qc_prop = get_proposal( high_qc.proposal_id ); + if (old_high_qc_prop == nullptr) + return false; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); + if (new_high_qc_prop == nullptr) + return false; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); - old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); - new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); - - if (old_high_qc_prop == _proposal_store.get().end()) return false; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); - if (new_high_qc_prop == _proposal_store.get().end()) return false; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); - - if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ + if (new_high_qc_prop->get_height() > old_high_qc_prop->get_height()) { bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); - if (quorum_met){ + if (quorum_met) { // "The caller does not need this updated on their high_qc structure -- g" //high_qc.quorum_met = true; @@ -664,8 +724,8 @@ namespace eosio { namespace hotstuff { //verify if leader changed - name current_leader = _pacemaker->get_leader() ; - name next_leader = _pacemaker->get_next_leader() ; + name current_leader = _pacemaker->get_leader(); + name next_leader = _pacemaker->get_next_leader(); if (current_leader != next_leader){ @@ -702,148 +762,112 @@ namespace eosio { namespace hotstuff { fc::sha256 upcoming_commit; - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) + final_on_qc_check = true; //if chain just launched or feature just activated else { std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - if (chain_length>=2){ + if (chain_length >= 2) { auto itr = current_qc_chain.begin(); hs_proposal_message b2 = *itr; - itr++; + ++itr; hs_proposal_message b1 = *itr; - if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; + if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) + upcoming_commit = b1.proposal_id; else { - - proposal_store_type::nth_index<0>::type::iterator p_itr; - - p_itr = _proposal_store.get().find( b1.parent_id ); - - upcoming_commit = p_itr->final_on_qc; + const hs_proposal_message *p = get_proposal( b1.parent_id ); + //EOS_ASSERT( p != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", b1.parent_id) ); + if (p != nullptr) { + upcoming_commit = p->final_on_qc; + } else { + if (_errors) ilog(" *** ${id} in is_node_safe did not find expected proposal id: ${proposal_id}", ("id",_id)("proposal_id", b1.parent_id)); + } } } //abstracted [...] - if (upcoming_commit == proposal.final_on_qc){ + if (upcoming_commit == proposal.final_on_qc) { final_on_qc_check = true; } } - if (proposal.get_height() > _v_height){ + if (proposal.get_height() > _v_height) { monotony_check = true; } if (_b_lock != NULL_PROPOSAL_ID){ //Safety check : check if this proposal extends the chain I'm locked on - if (extends(proposal.proposal_id, _b_lock)){ + if (extends(proposal.proposal_id, _b_lock)) { safety_check = true; } //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated - else { - proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); - proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); - - if (prop_justification->get_height() > b_lock->get_height()){ + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) { + liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated + } else { + const hs_proposal_message *b_lock = get_proposal( _b_lock ); + EOS_ASSERT( b_lock != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", _b_lock) ); + const hs_proposal_message *prop_justification = get_proposal( proposal.justify.proposal_id ); + EOS_ASSERT( prop_justification != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", proposal.justify.proposal_id) ); + + if (prop_justification->get_height() > b_lock->get_height()) { liveness_check = true; } } - } - else { - //if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); + } else { //if we're not locked on anything, means the protocol just activated or chain just launched liveness_check = true; safety_check = true; + + //if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); } -/* ilog(" === final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", - ("final_on_qc_check", final_on_qc_check) - ("monotony_check", monotony_check) - ("liveness_check", liveness_check) - ("safety_check", safety_check));*/ + //ilog(" === final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", + // ("final_on_qc_check", final_on_qc_check) + // ("monotony_check", monotony_check) + // ("liveness_check", liveness_check) + // ("safety_check", safety_check)); bool node_is_safe = final_on_qc_check && monotony_check && (liveness_check || safety_check); if (!node_is_safe) { - if (_errors) ilog(" *** node is NOT safe. Checks : final_on_qc: ${final_on_qc}, monotony_check: ${monotony_check}, liveness_check: ${liveness_check}, safety_check: ${safety_check})", - ("final_on_qc_check",final_on_qc_check) - ("monotony_check",monotony_check) - ("liveness_check",liveness_check) - ("safety_check",safety_check)); + if (_errors) + ilog(" *** node is NOT safe. Checks : final_on_qc: ${final_on_qc}, monotony_check: ${monotony_check}, liveness_check: ${liveness_check}, safety_check: ${safety_check})", + ("final_on_qc_check",final_on_qc_check) + ("monotony_check",monotony_check) + ("liveness_check",liveness_check) + ("safety_check",safety_check)); } - return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully + //return true if monotony check and at least one of liveness or safety check evaluated successfully + return final_on_qc_check && monotony_check && (liveness_check || safety_check); } //on proposal received, called from network thread void qc_chain::on_hs_proposal_msg(const hs_proposal_message & msg){ - std::exception_ptr eptr; - try{ - //ilog(" === ${id} qc on_hs_proposal_msg ===", ("id", _id)); - //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - process_proposal(msg); - //ilog(" === end of on_hs_proposal_msg"); - } - catch (...){ - if (_errors) ilog(" *** ${id} error during on_hs_proposal_msg", ("id",_id)); - eptr = std::current_exception(); // capture - } - handle_eptr(eptr); + process_proposal(msg); } //on vote received, called from network thread void qc_chain::on_hs_vote_msg(const hs_vote_message & msg){ - std::exception_ptr eptr; - try{ - //ilog(" === ${id} qc on_hs_vote_msg ===", ("id", _id)); - //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - process_vote(msg); - //ilog(" === end of on_hs_vote_msg"); - } - catch (...){ - if (_errors) ilog(" *** ${id} error during on_hs_vote_msg", ("id",_id)); - eptr = std::current_exception(); // capture - } - handle_eptr(eptr); + process_vote(msg); } //on new view received, called from network thread void qc_chain::on_hs_new_view_msg(const hs_new_view_message & msg){ - std::exception_ptr eptr; - try{ - //ilog(" === ${id} qc on_hs_new_view_msg ===", ("id", _id)); - //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - process_new_view(msg); - //ilog(" === end of on_hs_new_view_msg"); - } - catch (...){ - if (_errors) ilog(" *** ${id} error during on_hs_new_view_msg", ("id",_id)); - eptr = std::current_exception(); // capture - } - handle_eptr(eptr); + process_new_view(msg); } //on new block received, called from network thread void qc_chain::on_hs_new_block_msg(const hs_new_block_message & msg){ - std::exception_ptr eptr; - try{ - //ilog(" === ${id} qc on_hs_new_block_msg ===", ("id", _id)); - //std::lock_guard g( this-> _hotstuff_state_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - process_new_block(msg); - //ilog(" === end of on_hs_new_block_msg"); - } - catch (...){ - if (_errors) ilog(" *** ${id} error during on_hs_new_block_msg", ("id",_id)); - eptr = std::current_exception(); // capture - } - handle_eptr(eptr); + process_new_block(msg); } void qc_chain::update(const hs_proposal_message & proposal){ @@ -858,7 +882,8 @@ namespace eosio { namespace hotstuff { size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock); + const hs_proposal_message *b_lock = get_proposal( _b_lock ); + EOS_ASSERT( b_lock != nullptr || _b_lock == NULL_PROPOSAL_ID , chain_exception, "expected hs_proposal ${id} not found", ("id", _b_lock) ); //ilog(" === update_high_qc : proposal.justify ==="); update_high_qc(proposal.justify); @@ -882,13 +907,13 @@ namespace eosio { namespace hotstuff { //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock -/* if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height} b_lock height ${b_lock_height}", - ("id", _id) - ("_b_lock", _b_lock) - ("b_1_height", b_1.block_num()) - ("b_1_phase", b_1.phase_counter) - ("b_lock_height", b_lock->block_num()) - ("b_lock_phase", b_lock->phase_counter));*/ + //if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height} b_lock height ${b_lock_height}", + // ("id", _id) + // ("_b_lock", _b_lock) + // ("b_1_height", b_1.block_num()) + // ("b_1_phase", b_1.phase_counter) + // ("b_lock_height", b_lock->block_num()) + // ("b_lock_phase", b_lock->phase_counter)); if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); @@ -896,36 +921,38 @@ namespace eosio { namespace hotstuff { //if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); } - if (chain_length<3){ + if (chain_length < 3) { if (_log) ilog(" === ${id} qc chain length is 2",("id", _id)); return; } - itr++; + ++itr; hs_proposal_message b = *itr; -/* ilog(" === direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", - ("b_2.parent_id",b_2.parent_id) - ("b_1.proposal_id", b_1.proposal_id) - ("b_1.parent_id", b_1.parent_id) - ("b.proposal_id", b.proposal_id));*/ + //ilog(" === direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", + // ("b_2.parent_id",b_2.parent_id) + // ("b_1.proposal_id", b_1.proposal_id) + // ("b_1.parent_id", b_1.parent_id) + // ("b.proposal_id", b.proposal_id)); //direct parent relationship verification if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ if (_b_exec!= NULL_PROPOSAL_ID){ - proposal_store_type::nth_index<0>::type::iterator b_exec = _proposal_store.get().find( _b_exec); + const hs_proposal_message *b_exec = get_proposal( _b_exec ); + EOS_ASSERT( b_exec != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", _b_exec) ); if (b_exec->get_height() >= b.get_height() && b_exec->proposal_id != b.proposal_id){ - if (_errors) ilog(" *** ${id} finality violation detected at height ${block_num}, phase : ${phase}. Proposal ${proposal_id_1} conflicts with ${proposal_id_2}", - ("id", _id) - ("block_num", b.block_num()) - ("phase", b.phase_counter) - ("proposal_id_1", b.proposal_id) - ("proposal_id_2", b_exec->proposal_id)); + if (_errors) + ilog(" *** ${id} finality violation detected at height ${block_num}, phase : ${phase}. Proposal ${proposal_id_1} conflicts with ${proposal_id_2}", + ("id", _id) + ("block_num", b.block_num()) + ("phase", b.phase_counter) + ("proposal_id_1", b.proposal_id) + ("proposal_id_2", b_exec->proposal_id)); _b_finality_violation = b.proposal_id; @@ -954,60 +981,82 @@ namespace eosio { namespace hotstuff { void qc_chain::gc_proposals(uint64_t cutoff){ //ilog(" === garbage collection on old data"); +#ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE + ps_height_iterator psh_it = _proposal_stores_by_height.begin(); + while (psh_it != _proposal_stores_by_height.end()) { + uint64_t height = psh_it->first; + if (height <= cutoff) { + // remove all entries from _proposal_height for this proposal store + proposal_store & pstore = psh_it->second; + ps_iterator ps_it = pstore.begin(); + while (ps_it != pstore.end()) { + hs_proposal_message & p = ps_it->second; + ph_iterator ph_it = _proposal_height.find( p.proposal_id ); + EOS_ASSERT( ph_it != _proposal_height.end(), chain_exception, "gc_proposals internal error: no proposal height entry"); + uint64_t proposal_height = ph_it->second; + EOS_ASSERT(proposal_height == p.get_height(), chain_exception, "gc_proposals internal error: mismatched proposal height record"); // this check is unnecessary + _proposal_height.erase( ph_it ); + ++ps_it; + } + // then remove the entire proposal store + psh_it = _proposal_stores_by_height.erase( psh_it ); + } else { + ++psh_it; + } + } +#else auto end_itr = _proposal_store.get().upper_bound(cutoff); while (_proposal_store.get().begin() != end_itr){ - auto itr = _proposal_store.get().begin(); - -/* if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", - ("id", _id) - ("block_num", itr->block_num()) - ("phase_counter", itr->phase_counter) - ("block_id", itr->block_id) - ("proposal_id", itr->proposal_id));*/ - + //if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + // ("id", _id) + // ("block_num", itr->block_num()) + // ("phase_counter", itr->phase_counter) + // ("block_id", itr->block_id) + // ("proposal_id", itr->proposal_id)); _proposal_store.get().erase(itr); } +#endif } void qc_chain::commit(const hs_proposal_message & proposal){ -/* ilog(" === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", proposal.block_num()) - ("proposal_id", proposal.proposal_id) - ("block_id", proposal.block_id) - ("phase_counter", proposal.phase_counter) - ("parent_id", proposal.parent_id)); -*/ + //ilog(" === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + // ("block_num", proposal.block_num()) + // ("proposal_id", proposal.proposal_id) + // ("block_id", proposal.block_id) + // ("phase_counter", proposal.phase_counter) + // ("parent_id", proposal.parent_id)); + bool exec_height_check = false; - proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); + const hs_proposal_message *last_exec_prop = get_proposal( _b_exec ); + EOS_ASSERT( last_exec_prop != nullptr || _b_exec == NULL_PROPOSAL_ID, chain_exception, "expected hs_proposal ${id} not found", ("id", _b_exec) ); -/* ilog(" === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", last_exec_prop->block_num()) - ("proposal_id", last_exec_prop->proposal_id) - ("block_id", last_exec_prop->block_id) - ("phase_counter", last_exec_prop->phase_counter) - ("parent_id", last_exec_prop->parent_id));*/ + //ilog(" === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + // ("block_num", last_exec_prop->block_num()) + // ("proposal_id", last_exec_prop->proposal_id) + // ("block_id", last_exec_prop->block_id) + // ("phase_counter", last_exec_prop->phase_counter) + // ("parent_id", last_exec_prop->parent_id)); -/* ilog(" *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", - ("proposal_id_1", last_exec_prop->block_num()) - ("phase_counter_1", last_exec_prop->phase_counter) - ("proposal_id_2", proposal.block_num()) - ("phase_counter_2", proposal.phase_counter));*/ + //ilog(" *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", + // ("proposal_id_1", last_exec_prop->block_num()) + // ("phase_counter_1", last_exec_prop->phase_counter) + // ("proposal_id_2", proposal.block_num()) + // ("phase_counter_2", proposal.phase_counter)); - if (_b_exec==NULL_PROPOSAL_ID){ + if (_b_exec == NULL_PROPOSAL_ID) exec_height_check = true; - } - else exec_height_check = last_exec_prop->get_height() < proposal.get_height(); + else + exec_height_check = last_exec_prop->get_height() < proposal.get_height(); if (exec_height_check){ - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); - - if (p_itr != _proposal_store.get().end()){ + const hs_proposal_message *p = get_proposal( proposal.parent_id ); + if (p != nullptr) { //ilog(" === recursively committing" ); - commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first + commit(*p); //recursively commit all non-committed ancestor blocks sequentially first } //Execute commands [...] @@ -1020,13 +1069,13 @@ namespace eosio { namespace hotstuff { ("proposal_id", proposal.proposal_id)); } -/* else { - if (_errors) ilog(" *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id)); - }*/ + //else { + // if (_errors) ilog(" *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", + // ("id", _id) + // ("block_num", proposal.block_num()) + // ("phase_counter", proposal.phase_counter) + // ("proposal_id", proposal.proposal_id)); + //} } }} diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index ddde8132ce..40fb99ecdb 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -26,7 +26,7 @@ std::vector alternate_ids{ block_id_type("00000001d49031dba775bd2 block_id_type("00000003a5a001518358977e84a3f6abf87bf32a6e739ced9a7a3f6b0b8bf331")}; //list of unique replicas for our test -std::vector unique_replicas{ +std::vector unique_replicas { "bpa"_n, "bpb"_n, "bpc"_n, "bpd"_n, "bpe"_n, "bpf"_n, "bpg"_n, "bph"_n, "bpi"_n, @@ -38,39 +38,34 @@ std::vector unique_replicas{ class hotstuff_test_handler { public: - std::vector> _qc_chains; + std::vector>> _qc_chains; void initialize_qc_chains(test_pacemaker& tpm, std::vector info_loggers, std::vector error_loggers, std::vector replicas){ _qc_chains.clear(); - for (name r : replicas){ + // These used to be able to break the tests. Might be useful at some point. + _qc_chains.reserve( 100 ); + //_qc_chains.reserve( 10000 ); + //_qc_chains.reserve( 15 ); + //_qc_chains.reserve( replicas.size() ); - _qc_chains.push_back(std::make_pair(r, qc_chain())); + for (name r : replicas) { - } - - int counter = 0; - - auto itr = _qc_chains.begin(); - - while (itr!=_qc_chains.end()){ + bool log = std::find(info_loggers.begin(), info_loggers.end(), r) != info_loggers.end(); + bool err = std::find(error_loggers.begin(), error_loggers.end(), r) != error_loggers.end(); - bool log = false; - bool err = false; + //If you want to force logging everything + //log = err = true; - auto i_found = std::find(info_loggers.begin(), info_loggers.end(), replicas[counter]); - auto e_found = std::find(error_loggers.begin(), error_loggers.end(), replicas[counter]); + qc_chain *qcc_ptr = new qc_chain(r, &tpm, {r}, log, err); + std::shared_ptr qcc_shared_ptr(qcc_ptr); - if (i_found!=info_loggers.end()) log = true; - if (e_found!=error_loggers.end()) err = true; + _qc_chains.push_back( std::make_pair(r, qcc_shared_ptr) ); - itr->second.init(replicas[counter], tpm, {replicas[counter]}, log, err); - - itr++; - counter++; + tpm.register_qc_chain( r, qcc_shared_ptr ); } - } + } void print_msgs(std::vector msgs ){ @@ -123,29 +118,31 @@ class hotstuff_test_handler { std::cout << message; std::cout << "\n"; - auto qcc = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == bp; }); + auto qcc_entry = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == bp; }); - auto leaf_itr = qcc->second._proposal_store.get().find( qcc->second._b_leaf ); - auto qc_itr = qcc->second._proposal_store.get().find( qcc->second._high_qc.proposal_id ); - auto lock_itr = qcc->second._proposal_store.get().find( qcc->second._b_lock ); - auto exec_itr = qcc->second._proposal_store.get().find( qcc->second._b_exec ); + qc_chain & qcc = *qcc_entry->second.get(); + const hs_proposal_message *leaf = qcc.get_proposal( qcc._b_leaf ); + const hs_proposal_message *qc = qcc.get_proposal( qcc._high_qc.proposal_id ); + const hs_proposal_message *lock = qcc.get_proposal( qcc._b_lock ); + const hs_proposal_message *exec = qcc.get_proposal( qcc._b_exec ); - if (leaf_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << qcc->second._b_leaf.str() << " block_num : " << leaf_itr->block_num() << ", phase : " << unsigned(leaf_itr->phase_counter) << "\n"; + if (leaf != nullptr) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << qcc._b_leaf.str() << " block_num : " << leaf->block_num() << ", phase : " << unsigned(leaf->phase_counter) << "\n"; else std::cout << " - No b_leaf value " << "\n"; - if (qc_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current high_qc is : " << qcc->second._high_qc.proposal_id.str() << " block_num : " << qc_itr->block_num() << ", phase : " << unsigned(qc_itr->phase_counter) << "\n"; + if (qc != nullptr) std::cout << " - " << bp.to_string() << " current high_qc is : " << qcc._high_qc.proposal_id.str() << " block_num : " << qc->block_num() << ", phase : " << unsigned(qc->phase_counter) << "\n"; else std::cout << " - No high_qc value " << "\n"; - if (lock_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_lock is : " << qcc->second._b_lock.str() << " block_num : " << lock_itr->block_num() << ", phase : " << unsigned(lock_itr->phase_counter) << "\n"; + if (lock != nullptr) std::cout << " - " << bp.to_string() << " current _b_lock is : " << qcc._b_lock.str() << " block_num : " << lock->block_num() << ", phase : " << unsigned(lock->phase_counter) << "\n"; else std::cout << " - No b_lock value " << "\n"; - if (exec_itr != qcc->second._proposal_store.get().end()) std::cout << " - " << bp.to_string() << " current _b_exec is : " << qcc->second._b_exec.str() << " block_num : " << exec_itr->block_num() << ", phase : " << unsigned(exec_itr->phase_counter) << "\n"; + if (exec != nullptr) std::cout << " - " << bp.to_string() << " current _b_exec is : " << qcc._b_exec.str() << " block_num : " << exec->block_num() << ", phase : " << unsigned(exec->phase_counter) << "\n"; else std::cout << " - No b_exec value " << "\n"; std::cout << "\n"; } }; + BOOST_AUTO_TEST_SUITE(hotstuff) BOOST_AUTO_TEST_CASE(hotstuff_bitset) try { @@ -206,37 +203,37 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on first block) tpm.dispatch(""); //send proposal to replicas (precommit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) tpm.dispatch(""); //send proposal to replicas (commit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //propagating votes on new proposal (commitQC on first block) tpm.dispatch(""); //send proposal to replicas (decide on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //propagating votes on new proposal (decide on first block) @@ -246,51 +243,51 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { tpm.dispatch(""); //send proposal to replicas (prepare on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); tpm.dispatch(""); //send votes on proposal (prepareQC on second block) tpm.dispatch(""); //send proposal to replicas (precommit on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) tpm.dispatch(""); //send proposal to replicas (commit on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) tpm.dispatch(""); //send proposal to replicas (decide on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); tpm.dispatch(""); //send proposal to replicas (decide on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); //check bpb as well - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); } FC_LOG_AND_RETHROW(); @@ -318,19 +315,19 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.dispatch(""); //send proposal to replicas (prepare on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on first block) tpm.dispatch(""); //send proposal to replicas (precommit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.set_current_block_id(ids[1]); //second block @@ -338,19 +335,19 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.dispatch(""); //send proposal to replicas (prepare on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on second block) tpm.dispatch(""); //send proposal to replicas (precommit on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.set_current_block_id(ids[2]); //second block @@ -358,26 +355,26 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.dispatch(""); //propagating votes on new proposal (prepare on third block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //send votes on proposal (prepareQC on third block) tpm.dispatch(""); //propagating votes on new proposal (precommitQC on third block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); //check bpb as well - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); } FC_LOG_AND_RETHROW(); @@ -406,28 +403,28 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.dispatch(""); //send proposal to replicas (prepare on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on first block) tpm.dispatch(""); //send proposal to replicas (precommit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) tpm.dispatch(""); //send proposal to replicas (commit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.set_next_leader("bpb"_n); //leader is set to rotate on next block @@ -435,10 +432,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.dispatch(""); //send proposal to replicas (decide on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //propagating votes on new proposal (decide on first block) @@ -451,49 +448,49 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.dispatch(""); //send proposal to replicas (prepare on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //send votes on proposal (prepareQC on second block) tpm.dispatch(""); //send proposal to replicas (precommit on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) tpm.dispatch(""); //send proposal to replicas (commit on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) tpm.dispatch(""); //send proposal to replicas (decide on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second._b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpa as well - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpc as well - BOOST_CHECK_EQUAL(qcc_bpc->second._high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpc->second._b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpc->second._b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpc->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpc->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpc->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); } FC_LOG_AND_RETHROW(); @@ -522,19 +519,19 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { tpm.dispatch(""); //send proposal to replicas (prepare on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on first block) tpm.dispatch(""); //send proposal to replicas (precommit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) @@ -550,10 +547,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { tpm.dispatch(""); //send proposal to replicas (commit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.set_next_leader("bpi"_n); //leader is set to rotate on next block @@ -561,10 +558,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, "before reactivate"); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.activate("bpb"_n); tpm.activate("bpc"_n); @@ -586,30 +583,30 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpi"_n, ""); //ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on second block) tpm.dispatch(""); //send proposal to replicas (precommit on second block) //ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) tpm.dispatch(""); //send proposal to replicas (commit on second block) //ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) @@ -617,23 +614,23 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpa->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); //ht.print_bp_state("bpb"_n, ""); //check bpa as well - BOOST_CHECK_EQUAL(qcc_bpb->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpb->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); //ht.print_bp_state("bpi"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpi->second._high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpi->second._b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpi->second._b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(qcc_bpi->second->_high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(qcc_bpi->second->_b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(qcc_bpi->second->_b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second._b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); } FC_LOG_AND_RETHROW(); @@ -720,10 +717,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm1.dispatch(""); tpm1.dispatch(""); @@ -733,10 +730,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm1.dispatch(""); tpm1.dispatch(""); @@ -746,10 +743,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm1.dispatch(""); tpm1.dispatch(""); @@ -759,10 +756,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm1.set_current_block_id(ids[1]); //first block tpm2.set_current_block_id(alternate_ids[1]); //first block @@ -778,10 +775,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); tpm1.pipe(tpm2.dispatch("")); tpm1.dispatch(""); @@ -791,10 +788,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); tpm1.pipe(tpm2.dispatch("")); tpm1.dispatch(""); @@ -804,10 +801,10 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); tpm1.pipe(tpm2.dispatch("")); tpm1.dispatch(""); @@ -817,12 +814,12 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpe->second._high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpe->second._b_finality_violation.str(), std::string("5585accc44c753636d1381067c7f915d7fff2d33846aae04820abc055d952860")); + BOOST_CHECK_EQUAL(qcc_bpe->second->_b_finality_violation.str(), std::string("5585accc44c753636d1381067c7f915d7fff2d33846aae04820abc055d952860")); } FC_LOG_AND_RETHROW(); diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test_pacemaker.cpp index 9abe22a7d3..ddf91b6306 100644 --- a/libraries/hotstuff/test_pacemaker.cpp +++ b/libraries/hotstuff/test_pacemaker.cpp @@ -3,68 +3,54 @@ namespace eosio { namespace hotstuff { - void test_pacemaker::set_proposer(name proposer){ + void test_pacemaker::set_proposer(name proposer) { _proposer = proposer; }; - void test_pacemaker::set_leader(name leader){ + void test_pacemaker::set_leader(name leader) { _leader = leader; }; - void test_pacemaker::set_next_leader(name next_leader){ + void test_pacemaker::set_next_leader(name next_leader) { _next_leader = next_leader; }; - void test_pacemaker::set_finalizers(std::vector finalizers){ + void test_pacemaker::set_finalizers(std::vector finalizers) { _finalizers = finalizers; }; - void test_pacemaker::set_current_block_id(block_id_type id){ + void test_pacemaker::set_current_block_id(block_id_type id) { _current_block_id = id; }; - void test_pacemaker::set_quorum_threshold(uint32_t threshold){ + void test_pacemaker::set_quorum_threshold(uint32_t threshold) { _quorum_threshold = threshold; } - void test_pacemaker::add_message_to_queue(hotstuff_message msg){ + void test_pacemaker::add_message_to_queue(hotstuff_message msg) { _pending_message_queue.push_back(msg); } - void test_pacemaker::pipe(std::vector messages){ + void test_pacemaker::pipe(std::vector messages) { auto itr = messages.begin(); - while (itr != messages.end()){ + while (itr != messages.end()) { _pending_message_queue.push_back(*itr); itr++; } } - // Remove unused return value - //std::vector - void test_pacemaker::dispatch(std::string memo, int count){ - for (int i = 0 ; i < count ; i++){ + void test_pacemaker::dispatch(std::string memo, int count) { + for (int i = 0 ; i < count ; i++) { this->dispatch(memo); } } - std::vector test_pacemaker::dispatch(std::string memo){ - - int count = 1; - - //ilog(" === propagate ${count} messages", ("count", _pending_message_queue.size())); + std::vector test_pacemaker::dispatch(std::string memo) { std::vector dispatched_messages = _pending_message_queue; _message_queue = _pending_message_queue; - while (_pending_message_queue.begin()!=_pending_message_queue.end()){ - - auto itr = _pending_message_queue.end(); - itr--; - - _pending_message_queue.erase(itr); - } - - //ilog(" === propagate ${count} messages", ("count", _message_queue.size())); + _pending_message_queue.clear(); size_t proposals_count = 0; size_t votes_count = 0; @@ -72,214 +58,164 @@ namespace eosio { namespace hotstuff { size_t new_views_count = 0; auto msg_itr = _message_queue.begin(); - - while (msg_itr!=_message_queue.end()){ + while (msg_itr!=_message_queue.end()) { size_t v_index = msg_itr->second.index(); - if(v_index==0) proposals_count++; - if(v_index==1) votes_count++; - if(v_index==2) new_blocks_count++; - if(v_index==3) new_views_count++; - - //ilog(" === propagating message ${count} : type : ${index}", ("count", count) ("index", msg_itr->index())); - - if (msg_itr->second.index() == 0) on_hs_proposal_msg(msg_itr->first, std::get(msg_itr->second)); - else if (msg_itr->second.index() == 1) on_hs_vote_msg(msg_itr->first, std::get(msg_itr->second)); - else if (msg_itr->second.index() == 2) on_hs_new_block_msg(msg_itr->first, std::get(msg_itr->second)); - else if (msg_itr->second.index() == 3) on_hs_new_view_msg(msg_itr->first, std::get(msg_itr->second)); - - msg_itr++; - - //ilog(" === after erase"); - - count++; + if (v_index==0) + ++proposals_count; + else if (v_index==1) + ++votes_count; + else if (v_index==2) + ++new_blocks_count; + else if (v_index==3) + ++new_views_count; + else + throw std::runtime_error("unknown message variant"); + + if (msg_itr->second.index() == 0) + on_hs_proposal_msg(std::get(msg_itr->second), msg_itr->first); + else if (msg_itr->second.index() == 1) + on_hs_vote_msg(std::get(msg_itr->second), msg_itr->first); + else if (msg_itr->second.index() == 2) + on_hs_new_block_msg(std::get(msg_itr->second), msg_itr->first); + else if (msg_itr->second.index() == 3) + on_hs_new_view_msg(std::get(msg_itr->second), msg_itr->first); + else + throw std::runtime_error("unknown message variant"); + + ++msg_itr; } - //ilog(" === erase"); + _message_queue.clear(); - while (_message_queue.begin()!=_message_queue.end()){ - - auto itr = _message_queue.end(); - itr--; - - _message_queue.erase(itr); - } - - //ilog(" === after erase"); - - if (memo!=""){ + if (memo != "") { ilog(" === ${memo} : ", ("memo", memo)); } - ilog(" === pacemaker dispatched ${proposals} proposals, ${votes} votes, ${new_blocks} new_blocks, ${new_views} new_views", - ("proposals", proposals_count) - ("votes", votes_count) - ("new_blocks", new_blocks_count) - ("new_views", new_views_count)); + //ilog(" === pacemaker dispatched ${proposals} proposals, ${votes} votes, ${new_blocks} new_blocks, ${new_views} new_views", + // ("proposals", proposals_count) + // ("votes", votes_count) + // ("new_blocks", new_blocks_count) + // ("new_views", new_views_count)); return dispatched_messages; } - void test_pacemaker::activate(name replica){ - auto qc_itr = _qcc_store.get().find( replica.to_uint64_t() ); - if (qc_itr==_qcc_store.end()) throw std::runtime_error("replica not found"); - _qcc_store.modify(qc_itr, [&]( auto& qcc ){ - qcc._active = true; - }); + void test_pacemaker::activate(name replica) { + auto qc_itr = _qcc_store.find( replica ); + if (qc_itr == _qcc_store.end()) + throw std::runtime_error("replica not found"); + + _qcc_deactivated.erase(replica); } - void test_pacemaker::deactivate(name replica){ - auto qc_itr = _qcc_store.get().find( replica.to_uint64_t() ); - if (qc_itr==_qcc_store.end()) throw std::runtime_error("replica not found"); - _qcc_store.modify(qc_itr, [&]( auto& qcc ){ - qcc._active = false; - }); + void test_pacemaker::deactivate(name replica) { + auto qc_itr = _qcc_store.find( replica ); + if (qc_itr == _qcc_store.end()) + throw std::runtime_error("replica not found"); + + _qcc_deactivated.insert(replica); } - name test_pacemaker::get_proposer(){ + name test_pacemaker::get_proposer() { return _proposer; }; - name test_pacemaker::get_leader(){ + name test_pacemaker::get_leader() { return _leader; }; - name test_pacemaker::get_next_leader(){ + name test_pacemaker::get_next_leader() { return _next_leader; }; - std::vector test_pacemaker::get_finalizers(){ + std::vector test_pacemaker::get_finalizers() { return _finalizers; }; - block_id_type test_pacemaker::get_current_block_id(){ + block_id_type test_pacemaker::get_current_block_id() { return _current_block_id; }; - uint32_t test_pacemaker::get_quorum_threshold(){ + uint32_t test_pacemaker::get_quorum_threshold() { return _quorum_threshold; }; - void test_pacemaker::beat(){ - auto itr = _qcc_store.get().find( _proposer.to_uint64_t() ); - if (itr==_qcc_store.end()) throw std::runtime_error("proposer not found"); - itr->_qc_chain->on_beat(); + void test_pacemaker::beat() { + auto itr = _qcc_store.find( _proposer ); + if (itr == _qcc_store.end()) + throw std::runtime_error("proposer not found"); + std::shared_ptr & qcc_ptr = itr->second; + qcc_ptr->on_beat(); }; - void test_pacemaker::assign_qc_chain(name name, qc_chain& qcc){ - - //ilog("reg listener"); - - auto itr = _qcc_store.get().find( name.to_uint64_t() ); - - //ilog("got itr"); - - if (itr!=_qcc_store.end()){ + void test_pacemaker::register_qc_chain(name name, std::shared_ptr qcc_ptr) { + auto itr = _qcc_store.find( name ); + if (itr != _qcc_store.end()) throw std::runtime_error("duplicate qc chain"); - } - else { - - //ilog("new listener ${name}", ("name", name)); - - //_unique_replicas.push_back(name); - - indexed_qc_chain iqcc(name, &qcc); - - //iqcc._name = name; - //iqcc._active = true; - //iqcc._qc_chain = &qcc; - - //ilog(" === register_listener 1 ${my_producers}", ("my_producers", iqcc._qc_chain->_my_producers)); - - _qcc_store.insert(iqcc); - - //auto itr = _qcc_store.get().find( name.to_uint64_t() ); - - //ilog(" === register_listener 2 ${my_producers}", ("my_producers", itr->_qc_chain->_my_producers)); - } + else + _qcc_store.emplace( name, qcc_ptr ); }; - void test_pacemaker::send_hs_proposal_msg(name id, const hs_proposal_message & msg){ - //ilog("queuing hs_proposal_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); + void test_pacemaker::send_hs_proposal_msg(const hs_proposal_message & msg, name id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_vote_msg(name id, const hs_vote_message & msg){ - //ilog("queuing hs_vote_message : ${proposal_id} ", ("proposal_id", msg.proposal_id) ); + void test_pacemaker::send_hs_vote_msg(const hs_vote_message & msg, name id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_block_msg(name id, const hs_new_block_message & msg){ + void test_pacemaker::send_hs_new_block_msg(const hs_new_block_message & msg, name id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_view_msg(name id, const hs_new_view_message & msg){ + void test_pacemaker::send_hs_new_view_msg(const hs_new_view_message & msg, name id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::on_hs_proposal_msg(name id, const hs_proposal_message & msg){ - //ilog(" === on_hs_proposal_msg"); + void test_pacemaker::on_hs_proposal_msg(const hs_proposal_message & msg, name id) { auto qc_itr = _qcc_store.begin(); - while (qc_itr!=_qcc_store.end()){ - //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - - // never happens && redundant check - //if (qc_itr->_qc_chain == nullptr) throw std::runtime_error("ptr is null"); - - if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_proposal_msg(msg); - + while (qc_itr != _qcc_store.end()){ + const name & qcc_name = qc_itr->first; + std::shared_ptr & qcc_ptr = qc_itr->second; + if (qcc_ptr->_id != id && is_qc_chain_active(qcc_name) ) + qcc_ptr->on_hs_proposal_msg(msg); qc_itr++; } - //ilog(" === end on_hs_proposal_msg"); } - void test_pacemaker::on_hs_vote_msg(name id, const hs_vote_message & msg){ - //ilog(" === on_hs_vote_msg"); + void test_pacemaker::on_hs_vote_msg(const hs_vote_message & msg, name id) { auto qc_itr = _qcc_store.begin(); - while (qc_itr!=_qcc_store.end()){ - //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - - // never happens && redundant check - //if (qc_itr->_qc_chain == nullptr) throw std::runtime_error("ptr is null"); - - if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_vote_msg(msg); - + while (qc_itr != _qcc_store.end()) { + const name & qcc_name = qc_itr->first; + std::shared_ptr & qcc_ptr = qc_itr->second; + if (qcc_ptr->_id != id && is_qc_chain_active(qcc_name) ) + qcc_ptr->on_hs_vote_msg(msg); qc_itr++; } - //ilog(" === end on_hs_vote_msg"); } - void test_pacemaker::on_hs_new_block_msg(name id, const hs_new_block_message & msg){ - //ilog(" === on_hs_new_block_msg"); + void test_pacemaker::on_hs_new_block_msg(const hs_new_block_message & msg, name id) { auto qc_itr = _qcc_store.begin(); - while (qc_itr!=_qcc_store.end()){ - //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - - // never happens && redundant check - //if (qc_itr->_qc_chain == nullptr) throw std::runtime_error("ptr is null"); - - if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_block_msg(msg); - + while (qc_itr != _qcc_store.end()) { + const name & qcc_name = qc_itr->first; + std::shared_ptr & qcc_ptr = qc_itr->second; + if (qcc_ptr->_id != id && is_qc_chain_active(qcc_name) ) + qcc_ptr->on_hs_new_block_msg(msg); qc_itr++; } - //ilog(" === end on_hs_new_block_msg"); } - void test_pacemaker::on_hs_new_view_msg(name id, const hs_new_view_message & msg){ - //ilog(" === on_hs_new_view_msg"); + void test_pacemaker::on_hs_new_view_msg(const hs_new_view_message & msg, name id) { auto qc_itr = _qcc_store.begin(); - while (qc_itr!=_qcc_store.end()){ - //ilog("name : ${name}, active : ${active}", ("name", qc_itr->_name)("active", qc_itr->_active)); - - // never happens && redundant check - //if (qc_itr->_qc_chain == nullptr) throw std::runtime_error("ptr is null"); - - if (qc_itr->_qc_chain->_id != id && qc_itr->_active) qc_itr->_qc_chain->on_hs_new_view_msg(msg); - + while (qc_itr != _qcc_store.end()){ + const name & qcc_name = qc_itr->first; + std::shared_ptr & qcc_ptr = qc_itr->second; + if (qcc_ptr->_id != id && is_qc_chain_active(qcc_name) ) + qcc_ptr->on_hs_new_view_msg(msg); qc_itr++; } - //ilog(" === end on_hs_new_view_msg"); } }} diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 5f98ccd9ba..cada4fe816 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -410,9 +410,7 @@ class producer_plugin_impl : public std::enable_shared_from_this _chain_pacemaker; /* * HACK ALERT @@ -1224,9 +1222,10 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ my->_snapshot_scheduler.set_db_path(my->_snapshots_dir); my->_snapshot_scheduler.set_create_snapshot_fn([this](producer_plugin::next_function next){create_snapshot(next);}); - my->_chain_pacemaker.init(&chain); + EOS_ASSERT( !my->_chain_pacemaker, plugin_config_exception, "duplicate chain_pacemaker initialization" ); + my->_chain_pacemaker.emplace(&chain, my->_producers, true, true); - my->_qc_chain.init("main"_n, my->_chain_pacemaker, my->_producers, true, true); + //my->_qc_chain.init("main"_n, my->_chain_pacemaker, my->_producers, true, true); } FC_LOG_AND_RETHROW() } @@ -2800,20 +2799,24 @@ static auto maybe_make_debug_time_logger() -> std::optionalon_hs_vote_msg(*msg); }; void producer_plugin_impl::notify_hs_proposal_message( const hs_proposal_message_ptr& msg ){ - _chain_pacemaker.on_hs_proposal_msg("main"_n, *msg); + if (_chain_pacemaker) + _chain_pacemaker->on_hs_proposal_msg(*msg); }; -void producer_plugin_impl::notify_hs_new_view_message( const hs_new_view_message_ptr& msg){ - _chain_pacemaker.on_hs_new_view_msg("main"_n, *msg); +void producer_plugin_impl::notify_hs_new_view_message( const hs_new_view_message_ptr& msg ){ + if (_chain_pacemaker) + _chain_pacemaker->on_hs_new_view_msg(*msg); }; void producer_plugin_impl::notify_hs_new_block_message( const hs_new_block_message_ptr& msg ){ - _chain_pacemaker.on_hs_new_block_msg("main"_n, *msg); + if (_chain_pacemaker) + _chain_pacemaker->on_hs_new_block_msg(*msg); }; @@ -2872,7 +2875,8 @@ void producer_plugin_impl::produce_block() { // _qc_chain.create_new_view(*hbs); //we create a new view //} - _chain_pacemaker.beat(); + if (_chain_pacemaker) + _chain_pacemaker->beat(); br.total_time += fc::time_point::now() - start; From b6cd0caf88c9bf17866eeee3f52a4adca06dc92d Mon Sep 17 00:00:00 2001 From: fcecin Date: Mon, 1 May 2023 15:57:47 -0300 Subject: [PATCH 025/151] Removing hardcoded check for 'eosio' producer name. --- libraries/hotstuff/qc_chain.cpp | 10 ++++++---- plugins/producer_plugin/producer_plugin.cpp | 19 ++++++++++++++----- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 67e0e2d3b5..4bb4f684aa 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -601,10 +601,12 @@ namespace eosio { namespace hotstuff { //if (_log) ilog(" === ${id} on beat === ", ("id", _id)); - // FIXME/TODO: this hardcoded string name check is probably not exactly what we want here. - name current_producer = _pacemaker->get_leader(); - if (current_producer == "eosio"_n) - return; + // NOTE: These kinds of enable/disable decisions are now entirely pushed out + // of the hotstuff core and into the caller's hands. + // + //name current_producer = _pacemaker->get_leader(); + //if (current_producer == "eosio"_n) + // return; block_id_type current_block_id = _pacemaker->get_current_block_id(); diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index cada4fe816..9b7be7079e 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -362,6 +362,7 @@ class producer_plugin_impl : public std::enable_shared_from_this _signature_providers; @@ -886,7 +887,7 @@ void producer_plugin::set_program_options( boost::program_options::options_description producer_options; producer_options.add_options() - ("enable-stale-production,e", boost::program_options::bool_switch()->notifier([this](bool e){my->_production_enabled = e;}), "Enable block production, even if the chain is stale.") + ("enable-stale-production,e", boost::program_options::bool_switch()->notifier([this](bool e){my->_production_enabled = e; my->_enable_stale_production_config = e;}), "Enable block production, even if the chain is stale.") ("pause-on-startup,x", boost::program_options::bool_switch()->notifier([this](bool p){my->_pause_production = p;}), "Start this node in a state where production is paused") ("max-transaction-time", bpo::value()->default_value(30), "Limits the maximum time (in milliseconds) that is allowed a pushed transaction's code to execute before being considered invalid") @@ -1225,8 +1226,6 @@ void producer_plugin::plugin_initialize(const boost::program_options::variables_ EOS_ASSERT( !my->_chain_pacemaker, plugin_config_exception, "duplicate chain_pacemaker initialization" ); my->_chain_pacemaker.emplace(&chain, my->_producers, true, true); - //my->_qc_chain.init("main"_n, my->_chain_pacemaker, my->_producers, true, true); - } FC_LOG_AND_RETHROW() } void producer_plugin::plugin_startup() @@ -2875,8 +2874,18 @@ void producer_plugin_impl::produce_block() { // _qc_chain.create_new_view(*hbs); //we create a new view //} - if (_chain_pacemaker) - _chain_pacemaker->beat(); + if (_chain_pacemaker) { + + // FIXME/REVIEW: For now, we are not participating in the IF protocol as leaders + // when we have the enable-stale-production plugin configuration option set. + // Real public networks will have a controlled activation of the feature, but + // even then, it might be a good idea for stale-block proposing nodes to e.g. + // self-exclude from being hotstuff leaders. + if (!_enable_stale_production_config) + _chain_pacemaker->beat(); + else + ilog("producer plugin will not check for Instant Finality leader role due to enable-stale-production option set."); + } br.total_time += fc::time_point::now() - start; From 14a5b1300bf8179009c50121e17198b6769e7733 Mon Sep 17 00:00:00 2001 From: fcecin Date: Tue, 2 May 2023 19:05:37 -0300 Subject: [PATCH 026/151] hotstuff get_state(); v1/chain/get_finalizer_state API --- .../chain/include/eosio/chain/hotstuff.hpp | 20 ++++++ libraries/hotstuff/chain_pacemaker.cpp | 14 ++-- .../eosio/hotstuff/chain_pacemaker.hpp | 10 ++- .../include/eosio/hotstuff/qc_chain.hpp | 17 ++++- libraries/hotstuff/qc_chain.cpp | 71 +++++++++++++++++-- plugins/chain_api_plugin/chain_api_plugin.cpp | 4 ++ plugins/chain_plugin/chain_plugin.cpp | 25 +++++++ .../eosio/chain_plugin/chain_plugin.hpp | 41 +++++++++++ .../eosio/producer_plugin/producer_plugin.hpp | 4 +- plugins/producer_plugin/producer_plugin.cpp | 8 +++ 10 files changed, 199 insertions(+), 15 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 216d0e5c72..a29b87e3f5 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -69,6 +69,24 @@ namespace eosio { namespace chain { hs_new_view_message() = default; }; + struct finalizer_state { + + bool chained_mode = false; + fc::sha256 b_leaf = NULL_PROPOSAL_ID; + fc::sha256 b_lock = NULL_PROPOSAL_ID; + fc::sha256 b_exec = NULL_PROPOSAL_ID; + fc::sha256 b_finality_violation = NULL_PROPOSAL_ID; + block_id_type block_exec = NULL_BLOCK_ID; + block_id_type pending_proposal_block = NULL_BLOCK_ID; + uint32_t v_height = 0; + eosio::chain::quorum_certificate high_qc; + eosio::chain::quorum_certificate current_qc; + eosio::chain::extended_schedule schedule; + map proposals; + + finalizer_state() = default; + }; + using hs_proposal_message_ptr = std::shared_ptr; using hs_vote_message_ptr = std::shared_ptr; using hs_new_view_message_ptr = std::shared_ptr; @@ -77,7 +95,9 @@ namespace eosio { namespace chain { }} //eosio::chain FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); +FC_REFLECT(eosio::chain::extended_schedule, (producer_schedule)(bls_pub_keys)); FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(parent_id)(final_on_qc)(justify)(phase_counter)); FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify)); FC_REFLECT(eosio::chain::hs_new_view_message, (high_qc)); +FC_REFLECT(eosio::chain::finalizer_state, (chained_mode)(b_leaf)(b_lock)(b_exec)(b_finality_violation)(block_exec)(pending_proposal_block)(v_height)(high_qc)(current_qc)(schedule)(proposals)); diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index b9debdfcbe..e290dff85e 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -106,6 +106,10 @@ namespace eosio { namespace hotstuff { { } + void chain_pacemaker::get_state( finalizer_state & fs ) { + _qc_chain.get_state( fs ); // get_state() takes scare of finer-grained synchronization internally + } + name chain_pacemaker::get_proposer(){ const block_state_ptr& hbs = _chain->head_block_state(); return hbs->header.producer; @@ -145,7 +149,7 @@ namespace eosio { namespace hotstuff { void chain_pacemaker::beat(){ csc prof("beat"); - std::lock_guard g( _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); _qc_chain.on_beat(); prof.core_out(); @@ -173,7 +177,7 @@ namespace eosio { namespace hotstuff { void chain_pacemaker::on_hs_proposal_msg(const hs_proposal_message & msg){ csc prof("prop"); - std::lock_guard g( _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); _qc_chain.on_hs_proposal_msg(msg); prof.core_out(); @@ -181,7 +185,7 @@ namespace eosio { namespace hotstuff { void chain_pacemaker::on_hs_vote_msg(const hs_vote_message & msg){ csc prof("vote"); - std::lock_guard g( _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); _qc_chain.on_hs_vote_msg(msg); prof.core_out(); @@ -189,7 +193,7 @@ namespace eosio { namespace hotstuff { void chain_pacemaker::on_hs_new_block_msg(const hs_new_block_message & msg){ csc prof("nblk"); - std::lock_guard g( _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); _qc_chain.on_hs_new_block_msg(msg); prof.core_out(); @@ -197,7 +201,7 @@ namespace eosio { namespace hotstuff { void chain_pacemaker::on_hs_new_view_msg(const hs_new_view_message & msg){ csc prof("view"); - std::lock_guard g( _hotstuff_state_mutex ); + std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); _qc_chain.on_hs_new_view_msg(msg); prof.core_out(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index b7f8e32e6c..ca4dc734c2 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -1,5 +1,7 @@ #pragma once + #include + #include #include @@ -20,6 +22,8 @@ namespace eosio { namespace hotstuff { void on_hs_new_view_msg(const hs_new_view_message & msg); //new view msg event handler void on_hs_new_block_msg(const hs_new_block_message & msg); //new block msg event handler + void get_state( finalizer_state & fs ); + //base_pacemaker interface functions name get_proposer(); @@ -38,7 +42,11 @@ namespace eosio { namespace hotstuff { private: - std::mutex _hotstuff_state_mutex; + // This serializes all messages (high-level requests) to the qc_chain core. + // For maximum safety, the qc_chain core will only process one request at a time. + // These requests can come directly from the net threads, or indirectly from a + // dedicated finalizer thread (TODO: discuss). + std::mutex _hotstuff_global_mutex; chain::controller* _chain = nullptr; diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index d575c42443..04a621de4b 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -29,7 +29,6 @@ namespace eosio { namespace hotstuff { using boost::multi_index_container; using namespace boost::multi_index; - using namespace eosio::chain; class qc_chain { @@ -88,6 +87,8 @@ namespace eosio { namespace hotstuff { // returns false if proposal with that same ID already exists at the store of its height bool insert_proposal(const hs_proposal_message & proposal); + void get_state( finalizer_state & fs ); + uint32_t positive_bits_count(fc::unsigned_int value); fc::unsigned_int update_bitset(fc::unsigned_int value, name finalizer); @@ -147,6 +148,20 @@ namespace eosio { namespace hotstuff { private: + // This mutex synchronizes all writes to the data members of this qc_chain against + // get_state() calls (which ultimately come from e.g. the HTTP plugin). + // This could result in a HTTP query that gets the state of the core while it is + // in the middle of processing a given request, since this is not serializing + // against high-level message or request processing borders. + // If that behavior is not desired, we can instead synchronize this against a + // consistent past snapshot of the qc_chain's state for e.g. the HTTP plugin, + // which would be updated at the end of processing every request to the core + // that does alter the qc_chain (hotstuff protocol state). + // And if the chain_pacemaker::_hotstuff_global_mutex locking strategy is ever + // changed, then this probably needs to be reviewed as well. + // + std::mutex _state_mutex; + #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE // keep one proposal store (id -> proposal) by each height (height -> proposal store) typedef map proposal_store; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 4bb4f684aa..7b3e83e958 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -69,6 +69,7 @@ namespace eosio { namespace hotstuff { } bool qc_chain::insert_proposal(const hs_proposal_message & proposal) { + std::lock_guard g( _state_mutex ); #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE uint64_t proposal_height = proposal.get_height(); ps_height_iterator psh_it = _proposal_stores_by_height.find( proposal_height ); @@ -92,6 +93,41 @@ namespace eosio { namespace hotstuff { #endif } + void qc_chain::get_state( finalizer_state & fs ) { + std::lock_guard g( _state_mutex ); + fs.chained_mode = _chained_mode; + fs.b_leaf = _b_leaf; + fs.b_lock = _b_lock; + fs.b_exec = _b_exec; + fs.b_finality_violation = _b_finality_violation; + fs.block_exec = _block_exec; + fs.pending_proposal_block = _pending_proposal_block; + fs.v_height = _v_height; + fs.high_qc = _high_qc; + fs.current_qc = _current_qc; + fs.schedule = _schedule; +#ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE + ps_height_iterator psh_it = _proposal_stores_by_height.begin(); + while (psh_it != _proposal_stores_by_height.end()) { + proposal_store &pstore = psh_it->second; + ps_iterator ps_it = pstore.begin(); + while (ps_it != pstore.end()) { + fs.proposals.insert( *ps_it ); + ++ps_it; + } + ++psh_it; + } +#else + auto hgt_itr = _proposal_store.get().begin(); + auto end_itr = _proposal_store.get().end(); + while (hgt_itr != end_itr) { + const hs_proposal_message & p = *hgt_itr; + fs.proposals.emplace( p.proposal_id, p ); + ++hgt_itr; + } +#endif + } + uint32_t qc_chain::positive_bits_count(fc::unsigned_int value){ boost::dynamic_bitset b(21, value); uint32_t count = 0; @@ -191,6 +227,7 @@ namespace eosio { namespace hotstuff { } void qc_chain::reset_qc(fc::sha256 proposal_id){ + std::lock_guard g( _state_mutex ); //if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); _current_qc.proposal_id = proposal_id; _current_qc.quorum_met = false; @@ -297,7 +334,9 @@ namespace eosio { namespace hotstuff { hs_vote_message qc_chain::sign_proposal(const hs_proposal_message & proposal, name finalizer){ + std::unique_lock state_lock( _state_mutex ); _v_height = proposal.get_height(); + state_lock.unlock(); digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); @@ -473,25 +512,29 @@ namespace eosio { namespace hotstuff { // If quorum is already met, we don't need to do anything else. Otherwise, we aggregate the signature. if (!quorum_met){ + std::unique_lock state_lock( _state_mutex ); if (_current_qc.active_finalizers>0) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); else _current_qc.active_agg_sig = vote.sig; _current_qc.active_finalizers = update_bitset(_current_qc.active_finalizers, vote.finalizer); + state_lock.unlock(); quorum_met = is_quorum_met(_current_qc, _schedule, *p); if (quorum_met){ - _current_qc.quorum_met = true; - if (_log) ilog(" === ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", ("block_num", p->block_num()) ("phase_counter", p->phase_counter) ("proposal_id", vote.proposal_id) ("id", _id)); + state_lock.lock(); + _current_qc.quorum_met = true; + state_lock.unlock(); + //ilog(" === update_high_qc : _current_qc ==="); update_high_qc(_current_qc); @@ -514,9 +557,10 @@ namespace eosio { namespace hotstuff { //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); + state_lock.lock(); _pending_proposal_block = NULL_BLOCK_ID; - _b_leaf = proposal_candidate.proposal_id; + state_lock.unlock(); send_hs_proposal_msg(proposal_candidate); @@ -637,8 +681,9 @@ namespace eosio { namespace hotstuff { // ("proposal_id", _current_qc.proposal_id) // ("quorum_met", _current_qc.quorum_met)); //if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", current_block_id)); - + std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = current_block_id; + state_lock.unlock(); } else { @@ -653,9 +698,10 @@ namespace eosio { namespace hotstuff { //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (on_beat)", ("id", _id)); + std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = NULL_BLOCK_ID; - _b_leaf = proposal_candidate.proposal_id; + state_lock.unlock(); send_hs_proposal_msg(proposal_candidate); @@ -683,8 +729,10 @@ namespace eosio { namespace hotstuff { if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ + std::unique_lock state_lock( _state_mutex ); _high_qc = high_qc; _b_leaf = _high_qc.proposal_id; + state_lock.unlock(); //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } @@ -708,10 +756,11 @@ namespace eosio { namespace hotstuff { //ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); + std::unique_lock state_lock( _state_mutex ); _high_qc = high_qc; _high_qc.quorum_met = true; _b_leaf = _high_qc.proposal_id; - + state_lock.unlock(); //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } @@ -742,7 +791,9 @@ namespace eosio { namespace hotstuff { //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); + std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = NULL_BLOCK_ID; + state_lock.unlock(); hs_new_view_message new_view; @@ -919,7 +970,9 @@ namespace eosio { namespace hotstuff { if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); + std::unique_lock state_lock( _state_mutex ); _b_lock = b_1.proposal_id; //commit phase on b1 + state_lock.unlock(); //if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); } @@ -956,7 +1009,9 @@ namespace eosio { namespace hotstuff { ("proposal_id_1", b.proposal_id) ("proposal_id_2", b_exec->proposal_id)); + std::unique_lock state_lock( _state_mutex ); _b_finality_violation = b.proposal_id; + state_lock.unlock(); //protocol failure return; @@ -967,8 +1022,10 @@ namespace eosio { namespace hotstuff { //ilog(" === last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); + std::unique_lock state_lock( _state_mutex ); _b_exec = b.proposal_id; //decide phase on b _block_exec = b.block_id; + state_lock.unlock(); gc_proposals( b.get_height()-1); } @@ -982,7 +1039,7 @@ namespace eosio { namespace hotstuff { void qc_chain::gc_proposals(uint64_t cutoff){ //ilog(" === garbage collection on old data"); - + std::lock_guard g( _state_mutex ); #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE ps_height_iterator psh_it = _proposal_stores_by_height.begin(); while (psh_it != _proposal_stores_by_height.end()) { diff --git a/plugins/chain_api_plugin/chain_api_plugin.cpp b/plugins/chain_api_plugin/chain_api_plugin.cpp index ba5c92272b..a9432f50e8 100644 --- a/plugins/chain_api_plugin/chain_api_plugin.cpp +++ b/plugins/chain_api_plugin/chain_api_plugin.cpp @@ -127,6 +127,10 @@ void chain_api_plugin::plugin_startup() { }, appbase::exec_queue::read_only); } + _http_plugin.add_api({ + CHAIN_RO_CALL(get_finalizer_state, 200, http_params_types::no_params) + }, appbase::exec_queue::read_only); + _http_plugin.add_api({ { std::string("/v1/chain/get_block"), [ro_api, &_http_plugin, max_time=std::min(chain.get_abi_serializer_max_time(),max_response_time)] diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 26716786f2..838de57b5e 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2673,6 +2673,31 @@ read_only::get_consensus_parameters(const get_consensus_parameters_params&, cons return results; } +read_only::get_finalizer_state_results +read_only::get_finalizer_state(const get_finalizer_state_params&, const fc::time_point& deadline ) const { + get_finalizer_state_results results; + if ( producer_plug ) { // producer_plug is null when called from chain_plugin_tests.cpp and get_table_tests.cpp + finalizer_state fs; + producer_plug->get_finalizer_state( fs ); + results.chained_mode = fs.chained_mode; + results.b_leaf = fs.b_leaf; + results.b_lock = fs.b_lock; + results.b_exec = fs.b_exec; + results.b_finality_violation = fs.b_finality_violation; + results.block_exec = fs.block_exec; + results.pending_proposal_block = fs.pending_proposal_block; + results.v_height = fs.v_height; + results.high_qc = fs.high_qc; + results.current_qc = fs.current_qc; + results.schedule = fs.schedule; + for (auto proposal: fs.proposals) { + chain::hs_proposal_message & p = proposal.second; + results.proposals.push_back( hs_complete_proposal_message( p ) ); + } + } + return results; +} + } // namespace chain_apis fc::variant chain_plugin::get_log_trx_trace(const transaction_trace_ptr& trx_trace ) const { diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 8868fd3eaa..378ea5d2ad 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -716,6 +716,45 @@ class read_only { }; get_consensus_parameters_results get_consensus_parameters(const get_consensus_parameters_params&, const fc::time_point& deadline) const; + struct hs_complete_proposal_message { + fc::sha256 proposal_id; + chain::block_id_type block_id; + fc::sha256 parent_id; + fc::sha256 final_on_qc; + chain::quorum_certificate justify; + uint8_t phase_counter; + uint32_t block_number; + uint64_t block_height; + hs_complete_proposal_message( chain::hs_proposal_message p ) { + proposal_id = p.proposal_id; + block_id = p.block_id; + parent_id = p.parent_id; + final_on_qc = p.final_on_qc; + justify = p.justify; + phase_counter = p.phase_counter; + block_number = p.block_num(); + block_height = p.get_height(); + } + hs_complete_proposal_message() = delete; + }; + + using get_finalizer_state_params = empty; + struct get_finalizer_state_results { + bool chained_mode = false; + fc::sha256 b_leaf = chain::NULL_PROPOSAL_ID; + fc::sha256 b_lock = chain::NULL_PROPOSAL_ID; + fc::sha256 b_exec = chain::NULL_PROPOSAL_ID; + fc::sha256 b_finality_violation = chain::NULL_PROPOSAL_ID; + chain::block_id_type block_exec = chain::NULL_BLOCK_ID; + chain::block_id_type pending_proposal_block = chain::NULL_BLOCK_ID; + uint32_t v_height = 0; + chain::quorum_certificate high_qc; + chain::quorum_certificate current_qc; + chain::extended_schedule schedule; + vector proposals; + }; + get_finalizer_state_results get_finalizer_state(const get_finalizer_state_params&, const fc::time_point& deadline) const; + private: template void send_transient_transaction(const Params& params, next_function next, chain::transaction_metadata::trx_type trx_type) const; @@ -963,3 +1002,5 @@ FC_REFLECT( eosio::chain_apis::read_only::compute_transaction_results, (transact FC_REFLECT( eosio::chain_apis::read_only::send_read_only_transaction_params, (transaction)) FC_REFLECT( eosio::chain_apis::read_only::send_read_only_transaction_results, (transaction_id)(processed) ) FC_REFLECT( eosio::chain_apis::read_only::get_consensus_parameters_results, (chain_config)(wasm_config)) +FC_REFLECT( eosio::chain_apis::read_only::hs_complete_proposal_message, (proposal_id)(block_id)(parent_id)(final_on_qc)(justify)(phase_counter)(block_number)(block_height)) +FC_REFLECT( eosio::chain_apis::read_only::get_finalizer_state_results, (chained_mode)(b_leaf)(b_lock)(b_exec)(b_finality_violation)(block_exec)(pending_proposal_block)(v_height)(high_qc)(current_qc)(schedule)(proposals)) diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index a8da072579..fd08efc7b0 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -173,6 +173,8 @@ class producer_plugin : public appbase::plugin { void notify_hs_new_view_message( const chain::hs_new_view_message_ptr& msg); void notify_hs_new_block_message( const chain::hs_new_block_message_ptr& msg ); + bool get_finalizer_state(finalizer_state & fs) const; + fc::variants get_supported_protocol_features( const get_supported_protocol_features_params& params ) const; get_account_ram_corrections_result get_account_ram_corrections( const get_account_ram_corrections_params& params ) const; @@ -216,7 +218,7 @@ class producer_plugin : public appbase::plugin { static void set_test_mode(bool m) { test_mode_ = m; } private: inline static bool test_mode_{false}; // to be moved into appbase (application_base) - + std::shared_ptr my; }; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 9b7be7079e..49a9176633 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1624,6 +1624,14 @@ void producer_plugin::notify_hs_new_block_message( const hs_new_block_message_pt my->notify_hs_new_block_message(msg); }; +bool producer_plugin::get_finalizer_state( finalizer_state & fs ) const { + if (my->_chain_pacemaker) { + my->_chain_pacemaker->get_state( fs ); + return true; + } + return false; +} + fc::variants producer_plugin::get_supported_protocol_features( const get_supported_protocol_features_params& params ) const { fc::variants results; const chain::controller& chain = my->chain_plug->chain(); From 82e0cf19a01b97f44b0f3ef89f97462bcd53985e Mon Sep 17 00:00:00 2001 From: fcecin Date: Wed, 3 May 2023 10:29:17 -0300 Subject: [PATCH 027/151] cleos get finalizer_state; get_finalizer_state result key-name changes --- .../eosio/chain_plugin/chain_plugin.hpp | 22 +++++++++---------- programs/cleos/httpc.hpp | 1 + programs/cleos/main.cpp | 9 ++++++++ 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 378ea5d2ad..4d6941f1aa 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -717,14 +717,14 @@ class read_only { get_consensus_parameters_results get_consensus_parameters(const get_consensus_parameters_params&, const fc::time_point& deadline) const; struct hs_complete_proposal_message { - fc::sha256 proposal_id; - chain::block_id_type block_id; - fc::sha256 parent_id; - fc::sha256 final_on_qc; + fc::sha256 proposal_id = chain::NULL_PROPOSAL_ID; + chain::block_id_type block_id = chain::NULL_BLOCK_ID; + fc::sha256 parent_id = chain::NULL_PROPOSAL_ID; + fc::sha256 final_on_qc = chain::NULL_PROPOSAL_ID; chain::quorum_certificate justify; - uint8_t phase_counter; - uint32_t block_number; - uint64_t block_height; + uint8_t phase_counter = 0; + uint32_t block_height = 0; + uint64_t view_number = 0; hs_complete_proposal_message( chain::hs_proposal_message p ) { proposal_id = p.proposal_id; block_id = p.block_id; @@ -732,10 +732,10 @@ class read_only { final_on_qc = p.final_on_qc; justify = p.justify; phase_counter = p.phase_counter; - block_number = p.block_num(); - block_height = p.get_height(); + block_height = p.block_num(); + view_number = p.get_height(); } - hs_complete_proposal_message() = delete; + hs_complete_proposal_message() = default; // cleos requires this }; using get_finalizer_state_params = empty; @@ -1002,5 +1002,5 @@ FC_REFLECT( eosio::chain_apis::read_only::compute_transaction_results, (transact FC_REFLECT( eosio::chain_apis::read_only::send_read_only_transaction_params, (transaction)) FC_REFLECT( eosio::chain_apis::read_only::send_read_only_transaction_results, (transaction_id)(processed) ) FC_REFLECT( eosio::chain_apis::read_only::get_consensus_parameters_results, (chain_config)(wasm_config)) -FC_REFLECT( eosio::chain_apis::read_only::hs_complete_proposal_message, (proposal_id)(block_id)(parent_id)(final_on_qc)(justify)(phase_counter)(block_number)(block_height)) +FC_REFLECT( eosio::chain_apis::read_only::hs_complete_proposal_message, (proposal_id)(block_id)(parent_id)(final_on_qc)(justify)(phase_counter)(block_height)(view_number)) FC_REFLECT( eosio::chain_apis::read_only::get_finalizer_state_results, (chained_mode)(b_leaf)(b_lock)(b_exec)(b_finality_violation)(block_exec)(pending_proposal_block)(v_height)(high_qc)(current_qc)(schedule)(proposals)) diff --git a/programs/cleos/httpc.hpp b/programs/cleos/httpc.hpp index ad0b047cf2..27b3ed3eb9 100644 --- a/programs/cleos/httpc.hpp +++ b/programs/cleos/httpc.hpp @@ -21,6 +21,7 @@ namespace eosio { namespace client { namespace http { const string chain_func_base = "/v1/chain"; const string get_info_func = chain_func_base + "/get_info"; + const string get_finalizer_state_func = chain_func_base + "/get_finalizer_state"; const string get_transaction_status_func = chain_func_base + "/get_transaction_status"; const string get_consensus_parameters_func = chain_func_base + "/get_consensus_parameters"; const string send_txn_func = chain_func_base + "/send_transaction"; diff --git a/programs/cleos/main.cpp b/programs/cleos/main.cpp index ec9e9a058c..672c2ea011 100644 --- a/programs/cleos/main.cpp +++ b/programs/cleos/main.cpp @@ -2369,6 +2369,10 @@ protocol_features_t get_supported_protocol_features() { return results; }; +eosio::chain_apis::read_only::get_finalizer_state_results get_finalizer_state() { + return call(::default_url, get_finalizer_state_func).as(); +} + struct activate_subcommand { string feature_name_str; std::string account_str = "eosio"; @@ -3418,6 +3422,11 @@ int main( int argc, char** argv ) { std::cout << supported_features.names << std::endl; }); + // get finalizer state + get->add_subcommand("finalizer_state", localized("Get finalizer state"))->callback([] { + std::cout << fc::json::to_pretty_string(get_finalizer_state()) << std::endl; + }); + // set subcommand auto setSubcommand = app.add_subcommand("set", localized("Set or update blockchain state")); setSubcommand->require_subcommand(); From c63979f321537fa4c77446dd0118d11896059092 Mon Sep 17 00:00:00 2001 From: fcecin Date: Thu, 4 May 2023 16:57:23 -0300 Subject: [PATCH 028/151] separate leader and proposer (WIP) --- libraries/hotstuff/chain_pacemaker.cpp | 69 +++++- .../include/eosio/hotstuff/qc_chain.hpp | 3 +- libraries/hotstuff/qc_chain.cpp | 209 ++++++++++-------- libraries/hotstuff/test/test_hotstuff.cpp | 123 +++++++++++ .../eosio/chain_plugin/chain_plugin.hpp | 2 +- plugins/producer_plugin/producer_plugin.cpp | 11 +- 6 files changed, 315 insertions(+), 102 deletions(-) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index e290dff85e..6c7cb16878 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -112,12 +112,77 @@ namespace eosio { namespace hotstuff { name chain_pacemaker::get_proposer(){ const block_state_ptr& hbs = _chain->head_block_state(); - return hbs->header.producer; + name n = hbs->header.producer; + return n; } name chain_pacemaker::get_leader(){ const block_state_ptr& hbs = _chain->head_block_state(); - return hbs->header.producer; + name n = hbs->header.producer; + +/* + // FIXME/REMOVE: simple device to test proposer/leader + // separation using the net code. + // Given the name of who's going to be the proposer + // (which is the head block's producer), we swap the + // leader name here for someone else. + // This depends on your configuration files for the + // various nodeos instances you are using to test, + // specifically the producer names associated with + // each nodeos instance. + // This works for a setup with 21 producer names + // interleaved between two nodeos test instances. + // i.e. nodeos #1 has bpa, bpc, bpe ... + // nodeos #2 has bpb, bpd, bpf ... + if (n == "bpa"_n) { + n = "bpb"_n; + } else if (n == "bpb"_n) { + n = "bpa"_n; + } else if (n == "bpc"_n) { + n = "bpd"_n; + } else if (n == "bpd"_n) { + n = "bpc"_n; + } else if (n == "bpe"_n) { + n = "bpf"_n; + } else if (n == "bpf"_n) { + n = "bpe"_n; + } else if (n == "bpg"_n) { + n = "bph"_n; + } else if (n == "bph"_n) { + n = "bpg"_n; + } else if (n == "bpi"_n) { + n = "bpj"_n; + } else if (n == "bpj"_n) { + n = "bpi"_n; + } else if (n == "bpk"_n) { + n = "bpl"_n; + } else if (n == "bpl"_n) { + n = "bpk"_n; + } else if (n == "bpm"_n) { + n = "bpn"_n; + } else if (n == "bpn"_n) { + n = "bpm"_n; + } else if (n == "bpo"_n) { + n = "bpp"_n; + } else if (n == "bpp"_n) { + n = "bpo"_n; + } else if (n == "bpq"_n) { + n = "bpr"_n; + } else if (n == "bpr"_n) { + n = "bpq"_n; + } else if (n == "bps"_n) { + n = "bpt"_n; + } else if (n == "bpt"_n) { + n = "bps"_n; + } else if (n == "bpu"_n) { + // odd one out; can be whomever that is not in the same nodeos (it does not + // actually matter; we just want to make sure we are stressing the system by + // never allowing the proposer and leader to fall on the same nodeos instance). + n = "bpt"_n; + } +*/ + + return n; } name chain_pacemaker::get_next_leader(){ diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 04a621de4b..54126e8a28 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -122,8 +122,7 @@ namespace eosio { namespace hotstuff { void on_beat(); //handler for pacemaker beat() - // returns true if quorum_met was recalculated in this call and it evaluated to true; returns false in all other cases - bool update_high_qc(const eosio::chain::quorum_certificate & high_qc); //check if update to our high qc is required + void update_high_qc(const eosio::chain::quorum_certificate & high_qc); //check if update to our high qc is required void leader_rotation_check(); //check if leader rotation is required diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 7b3e83e958..214a8747af 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -579,7 +579,81 @@ namespace eosio { namespace hotstuff { } void qc_chain::process_new_block(const hs_new_block_message & msg){ - //ilog(" === Process new block ==="); + + // If I'm not a leader, I probably don't care about hs-new-block messages. + // TODO: check for a need to gossip/rebroadcast even if it's not for us (maybe here, maybe somewhere else). + if (! am_i_leader()) { + + //FIXME delete + ilog(" === ${id} process_new_block === discarding because I'm not the leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); + + return; + } + + //FIXME comment out + //if (_log) + ilog(" === ${id} process_new_block === am leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); + + + + // FIXME/REVIEW/TODO: What to do with the received msg.justify? + // + //------------------------------------ + // + // This triggers with the simple networked test: + // + //if (_high_qc.proposal_id != msg.justify.proposal_id) { + // ilog(" === discarding hs_new_block message, _high_qc is different: ${qc}", ("qc",_high_qc)); + // return; + //} + // + //------------------------------------ + // + // This makes it work "better", sometimes completing the 3rd phase for an ever-increasing block number, + // but doesn't look like it is doing what we want: + // + update_high_qc(msg.justify); + + + + if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false) { + + //FIXME comment out + if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", + ("id", _id) + ("proposal_id", _current_qc.proposal_id) + ("quorum_met", _current_qc.quorum_met)); + if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", msg.block_id)); + + std::unique_lock state_lock( _state_mutex ); + _pending_proposal_block = msg.block_id; + state_lock.unlock(); + + } else { + + //FIXME comment out + if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", + ("id", _id) + ("proposal_id", _current_qc.proposal_id) + ("quorum_met", _current_qc.quorum_met)); + + hs_proposal_message proposal_candidate = new_proposal_candidate( msg.block_id, 0 ); + + reset_qc(proposal_candidate.proposal_id); + + //FIXME comment out + if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_new_block)", ("id", _id)); + + std::unique_lock state_lock( _state_mutex ); + _pending_proposal_block = NULL_BLOCK_ID; + _b_leaf = proposal_candidate.proposal_id; + state_lock.unlock(); + + send_hs_proposal_msg(proposal_candidate); + + //FIXME comment out + if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); + } } void qc_chain::send_hs_proposal_msg(const hs_proposal_message & msg){ @@ -639,90 +713,50 @@ namespace eosio { namespace hotstuff { return false; } + // Invoked when we could perhaps make a proposal to the network (or to ourselves, if we are the leader). void qc_chain::on_beat(){ - //auto start = fc::time_point::now(); - - //if (_log) ilog(" === ${id} on beat === ", ("id", _id)); - - // NOTE: These kinds of enable/disable decisions are now entirely pushed out - // of the hotstuff core and into the caller's hands. + // Non-proposing leaders do not care about beat(void), because leaders react to a block proposal + // which comes from processing an incoming new block message from a proposer instead. + // beat(void) is called by the pacemaker, which decides when it's time to check whether we are + // proposers that should check whether as proposers we should propose a new hotstuff block to + // the network (or to ourselves, which is faster and doesn't require the bandwidth of an additional + // gossip round for a new proposed block). + // The current criteria for a leader selecting a proposal among all proposals it receives is to go + // with the first valid one that it receives. So if a proposer is also a leader, it silently goes + // with its own proposal, which is hopefully valid at the point of generation which is also the + // point of consumption. // - //name current_producer = _pacemaker->get_leader(); - //if (current_producer == "eosio"_n) - // return; + if (! am_i_proposer()) + return; block_id_type current_block_id = _pacemaker->get_current_block_id(); - //ilog(" === qc chain on_beat ${my_producers}", ("my_producers", _my_producers)); + hs_new_block_message block_candidate = new_block_candidate( current_block_id ); - bool am_proposer = am_i_proposer(); - bool am_leader = am_i_leader(); - - //if (_log) ilog(" === ${id} am_proposer = ${am_proposer}", ("am_proposer", am_proposer)("id", _id)); - //if (_log) ilog(" === ${id} am_leader = ${am_leader}", ("am_leader", am_leader)("id", _id)); + if (am_i_leader()) { - if (!am_proposer && !am_leader){ - return; //nothing to do - } + // I am the proposer; so this assumes that no additional proposal validation is required. - //if I am the leader - if (am_leader) { - - //if I'm not also the proposer, perform block validation as required - if (!am_proposer){ - //TODO: extra validation? - } - - if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false) { - - //if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", - // ("id", _id) - // ("proposal_id", _current_qc.proposal_id) - // ("quorum_met", _current_qc.quorum_met)); - //if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", current_block_id)); - std::unique_lock state_lock( _state_mutex ); - _pending_proposal_block = current_block_id; - state_lock.unlock(); - - } else { - - //if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", - // ("id", _id) - // ("proposal_id", _current_qc.proposal_id) - // ("quorum_met", _current_qc.quorum_met)); - - hs_proposal_message proposal_candidate = new_proposal_candidate(current_block_id, 0 ); - - reset_qc(proposal_candidate.proposal_id); - - //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (on_beat)", ("id", _id)); - - std::unique_lock state_lock( _state_mutex ); - _pending_proposal_block = NULL_BLOCK_ID; - _b_leaf = proposal_candidate.proposal_id; - state_lock.unlock(); + //FIXME delete + ilog(" === I am a leader-proposer that is proposing a block for itself to lead"); - send_hs_proposal_msg(proposal_candidate); - - //if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); - } + // Hardwired consumption by self; no networking. + process_new_block( block_candidate ); } else { - //if I'm only a proposer and not the leader, I send a new block message - hs_new_block_message block_candidate = new_block_candidate(current_block_id); - //ilog(" === broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); + // I'm only a proposer and not the leader; send a new-block-proposal message out to + // the network, until it reaches the leader. - send_hs_new_block_msg(block_candidate); - } + //FIXME comment out + ilog(" === broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); - //auto total_time = fc::time_point::now() - start; - //if (_log) ilog(" ... on_beat() total time : ${total_time}", ("total_time", total_time)); - //ilog(" === end of on_beat"); + send_hs_new_block_msg( block_candidate ); + } } - bool qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ + void qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ //ilog(" === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); // if new high QC is higher than current, update to new @@ -735,40 +769,31 @@ namespace eosio { namespace hotstuff { state_lock.unlock(); //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); - } - else { - + } else { const hs_proposal_message *old_high_qc_prop = get_proposal( _high_qc.proposal_id ); const hs_proposal_message *new_high_qc_prop = get_proposal( high_qc.proposal_id ); if (old_high_qc_prop == nullptr) - return false; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); + return; if (new_high_qc_prop == nullptr) - return false; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); - - if (new_high_qc_prop->get_height() > old_high_qc_prop->get_height()) { + return; - bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); - - if (quorum_met) { - - // "The caller does not need this updated on their high_qc structure -- g" - //high_qc.quorum_met = true; + if (new_high_qc_prop->get_height() > old_high_qc_prop->get_height() + && is_quorum_met(high_qc, _schedule, *new_high_qc_prop)) + { + // "The caller does not need this updated on their high_qc structure" -- g + //high_qc.quorum_met = true; - //ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); + //ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); - std::unique_lock state_lock( _state_mutex ); - _high_qc = high_qc; - _high_qc.quorum_met = true; - _b_leaf = _high_qc.proposal_id; - state_lock.unlock(); - //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); - } + std::unique_lock state_lock( _state_mutex ); + _high_qc = high_qc; + _high_qc.quorum_met = true; + _b_leaf = _high_qc.proposal_id; + state_lock.unlock(); - return quorum_met; + //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } } - - return false; } void qc_chain::leader_rotation_check(){ diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 40fb99ecdb..1f9c5cc835 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -823,4 +823,127 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { } FC_LOG_AND_RETHROW(); +BOOST_AUTO_TEST_CASE(hotstuff_6) try { + + //test simple separation between the (single) proposer and the leader; includes one leader rotation + + test_pacemaker tpm; + + hotstuff_test_handler ht; + + ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n},unique_replicas); + + tpm.set_proposer("bpg"_n); // can be any proposer that's not the leader for this test + tpm.set_leader("bpa"_n); + tpm.set_next_leader("bpa"_n); + tpm.set_finalizers(unique_replicas); + + auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + auto qcc_bpc = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpc"_n; }); + + tpm.set_current_block_id(ids[0]); //first block + + tpm.beat(); //produce first block + + ilog("getting first "); + + tpm.dispatch(""); //get the first block from the proposer to the leader + + tpm.dispatch(""); //send proposal to replicas (prepare on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on first block) + + tpm.dispatch(""); //send proposal to replicas (precommit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) + + tpm.dispatch(""); //send proposal to replicas (commit on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.set_next_leader("bpb"_n); //leader is set to rotate on next block + + tpm.dispatch(""); //propagating votes on new proposal (commitQC on first block) + + tpm.dispatch(""); //send proposal to replicas (decide on first block) + + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.dispatch(""); //propagating votes on new proposal (decide on first block) + + tpm.set_proposer("bpm"_n); // can be any proposer that's not the leader for this test + tpm.set_leader("bpb"_n); //leader has rotated + + tpm.set_current_block_id(ids[1]); //second block + + tpm.beat(); //produce second block + + tpm.dispatch(""); //get the second block from the proposer to the leader + + tpm.dispatch(""); //send proposal to replicas (prepare on second block) + + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + + tpm.dispatch(""); //send votes on proposal (prepareQC on second block) + + tpm.dispatch(""); //send proposal to replicas (precommit on second block) + + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) + + tpm.dispatch(""); //send proposal to replicas (commit on second block) + + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + + tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) + + tpm.dispatch(""); //send proposal to replicas (decide on second block) + + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + + //check bpa as well + BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + + //check bpc as well + BOOST_CHECK_EQUAL(qcc_bpc->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(qcc_bpc->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(qcc_bpc->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + + BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + +} FC_LOG_AND_RETHROW(); + + BOOST_AUTO_TEST_SUITE_END() diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 4d6941f1aa..ef0e114978 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -725,7 +725,7 @@ class read_only { uint8_t phase_counter = 0; uint32_t block_height = 0; uint64_t view_number = 0; - hs_complete_proposal_message( chain::hs_proposal_message p ) { + hs_complete_proposal_message( const chain::hs_proposal_message & p ) { proposal_id = p.proposal_id; block_id = p.block_id; parent_id = p.parent_id; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 49a9176633..91f2e84b8d 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -2884,15 +2884,16 @@ void producer_plugin_impl::produce_block() { if (_chain_pacemaker) { - // FIXME/REVIEW: For now, we are not participating in the IF protocol as leaders + // FIXME/REVIEW: For now, we are not participating in the IF protocol as proposers // when we have the enable-stale-production plugin configuration option set. - // Real public networks will have a controlled activation of the feature, but - // even then, it might be a good idea for stale-block proposing nodes to e.g. - // self-exclude from being hotstuff leaders. + // NOTE: This entire feature will likely disappear (deleted) before delivery, as + // hotstuff activation only takes place, realistically, after the + // stale-block-production producing/proposing boot node has been gone. + // Stale producing nodes being hotstuff leaders is probably fine. if (!_enable_stale_production_config) _chain_pacemaker->beat(); else - ilog("producer plugin will not check for Instant Finality leader role due to enable-stale-production option set."); + ilog("producer plugin will not check for Instant Finality proposer (and maybe also leader) role due to enable-stale-production option set."); } br.total_time += fc::time_point::now() - start; From 48826a38c41ccdb9a0827157e48766ee35dd717c Mon Sep 17 00:00:00 2001 From: fcecin Date: Sun, 7 May 2023 10:06:01 -0300 Subject: [PATCH 029/151] Fixed networked leader/proposer separation tester; qc_chain trace logging --- libraries/hotstuff/chain_pacemaker.cpp | 21 +- .../eosio/hotstuff/chain_pacemaker.hpp | 4 + libraries/hotstuff/qc_chain.cpp | 328 ++++++++++-------- libraries/hotstuff/test/test_hotstuff.cpp | 2 - 4 files changed, 212 insertions(+), 143 deletions(-) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 6c7cb16878..4394929ff7 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -116,10 +116,7 @@ namespace eosio { namespace hotstuff { return n; } - name chain_pacemaker::get_leader(){ - const block_state_ptr& hbs = _chain->head_block_state(); - name n = hbs->header.producer; - + name chain_pacemaker::debug_leader_remap(name n) { /* // FIXME/REMOVE: simple device to test proposer/leader // separation using the net code. @@ -181,6 +178,15 @@ namespace eosio { namespace hotstuff { n = "bpt"_n; } */ + return n; + } + + name chain_pacemaker::get_leader(){ + const block_state_ptr& hbs = _chain->head_block_state(); + name n = hbs->header.producer; + + // FIXME/REMOVE: testing leader/proposer separation + n = debug_leader_remap(n); return n; } @@ -189,7 +195,12 @@ namespace eosio { namespace hotstuff { const block_state_ptr& hbs = _chain->head_block_state(); block_timestamp_type next_block_time = hbs->header.timestamp.next(); producer_authority p_auth = hbs->get_scheduled_producer(next_block_time); - return p_auth.producer_name; + name n = p_auth.producer_name; + + // FIXME/REMOVE: testing leader/proposer separation + n = debug_leader_remap(n); + + return n; } std::vector chain_pacemaker::get_finalizers(){ diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index ca4dc734c2..c4a872a175 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -42,6 +42,10 @@ namespace eosio { namespace hotstuff { private: + //FIXME/REMOVE: for testing/debugging only + name debug_leader_remap(name n); + + // This serializes all messages (high-level requests) to the qc_chain core. // For maximum safety, the qc_chain core will only process one request at a time. // These requests can come directly from the net threads, or indirectly from a diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 214a8747af..dabe92191d 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -41,6 +41,12 @@ -- skip BPs without a bls key in the selection, new host functions are available */ + +// FIXME/REMOVE: remove all of this tracing +// Enables extra logging to help with debugging +//#define QC_CHAIN_TRACE_DEBUG + + namespace eosio { namespace hotstuff { const hs_proposal_message* qc_chain::get_proposal(fc::sha256 proposal_id) { @@ -138,9 +144,12 @@ namespace eosio { namespace hotstuff { } fc::unsigned_int qc_chain::update_bitset(fc::unsigned_int value, name finalizer ) { - //ilog(" === update bitset ${value} ${finalizer}", - // ("value", value) - // ("finalizer", finalizer)); + +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === update bitset ${value} ${finalizer}", + ("value", value) + ("finalizer", finalizer)); +#endif boost::dynamic_bitset b( 21, value ); vector finalizers = _pacemaker->get_finalizers(); @@ -148,17 +157,19 @@ namespace eosio { namespace hotstuff { if (finalizers[i] == finalizer) { b.flip(i); - //ilog(" === finalizer found ${finalizer} new value : ${value}", - // ("finalizer", finalizer) - // ("value", b.to_ulong())); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === finalizer found ${finalizer} new value : ${value}", + ("finalizer", finalizer) + ("value", b.to_ulong())); +#endif return b.to_ulong(); } } - - //ilog(" *** finalizer not found ${finalizer}", - // ("finalizer", finalizer)); - +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" *** finalizer not found ${finalizer}", + ("finalizer", finalizer)); +#endif throw std::runtime_error("qc_chain internal error: finalizer not found"); } @@ -228,7 +239,9 @@ namespace eosio { namespace hotstuff { void qc_chain::reset_qc(fc::sha256 proposal_id){ std::lock_guard g( _state_mutex ); - //if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); +#endif _current_qc.proposal_id = proposal_id; _current_qc.quorum_met = false; _current_qc.active_finalizers = 0; @@ -287,8 +300,9 @@ namespace eosio { namespace hotstuff { return true; //skip evaluation if we've already verified quorum was met } else { - //ilog(" === qc : ${qc}", ("qc", qc)); - +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === qc : ${qc}", ("qc", qc)); +#endif // If the caller wants to update the quorum_met flag on its "qc" object, it will have to do so // based on the return value of this method, since "qc" here is const. return evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); @@ -448,11 +462,13 @@ namespace eosio { namespace hotstuff { hs_vote_message v_msg = sign_proposal(proposal, *prod_itr); - //if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", - // ("id", _id) - // ("block_num", proposal.block_num()) - // ("phase_counter", proposal.phase_counter) - // ("proposal_id", proposal.proposal_id)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id)); +#endif //send_hs_vote_msg(v_msg); msgs.push_back(v_msg); @@ -463,11 +479,13 @@ namespace eosio { namespace hotstuff { } } - //else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", - // ("id", _id) - // ("block_num", proposal.block_num()) - // ("phase_counter", proposal.phase_counter) - // ("proposal_id", proposal.proposal_id)); +#ifdef QC_CHAIN_TRACE_DEBUG + else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id)); +#endif //update internal state update(proposal); @@ -493,9 +511,9 @@ namespace eosio { namespace hotstuff { if (!am_leader) return; - - //ilog(" === Process vote from ${finalizer} : current bitset ${value}" , ("finalizer", vote.finalizer)("value", _current_qc.active_finalizers)); - +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === Process vote from ${finalizer} : current bitset ${value}" , ("finalizer", vote.finalizer)("value", _current_qc.active_finalizers)); +#endif // only leader need to take action on votes if (vote.proposal_id != _current_qc.proposal_id) return; @@ -543,9 +561,9 @@ namespace eosio { namespace hotstuff { //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet if (_chained_mode == false && p->phase_counter < 3) { - - //if (_log) ilog(" === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); - +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); +#endif hs_proposal_message proposal_candidate; if (_pending_proposal_block == NULL_BLOCK_ID) @@ -554,17 +572,18 @@ namespace eosio { namespace hotstuff { proposal_candidate = new_proposal_candidate( _pending_proposal_block, 0 ); reset_qc(proposal_candidate.proposal_id); - - //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); - +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); +#endif state_lock.lock(); _pending_proposal_block = NULL_BLOCK_ID; _b_leaf = proposal_candidate.proposal_id; state_lock.unlock(); send_hs_proposal_msg(proposal_candidate); - - //if (_log) ilog(" === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); +#endif } } } @@ -574,7 +593,9 @@ namespace eosio { namespace hotstuff { } void qc_chain::process_new_view(const hs_new_view_message & msg){ - //if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", new_view.high_qc)("id", _id)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", msg.high_qc)("id", _id)); +#endif update_high_qc(msg.high_qc); } @@ -584,66 +605,54 @@ namespace eosio { namespace hotstuff { // TODO: check for a need to gossip/rebroadcast even if it's not for us (maybe here, maybe somewhere else). if (! am_i_leader()) { - //FIXME delete +#ifdef QC_CHAIN_TRACE_DEBUG ilog(" === ${id} process_new_block === discarding because I'm not the leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); - +#endif return; } - //FIXME comment out - //if (_log) - ilog(" === ${id} process_new_block === am leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); - - +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} process_new_block === am leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); +#endif - // FIXME/REVIEW/TODO: What to do with the received msg.justify? - // - //------------------------------------ - // - // This triggers with the simple networked test: + // ------------------------------------------------------------------ // - //if (_high_qc.proposal_id != msg.justify.proposal_id) { - // ilog(" === discarding hs_new_block message, _high_qc is different: ${qc}", ("qc",_high_qc)); - // return; - //} + // FIXME/REVIEW/TODO: What to do with the received msg.justify? // - //------------------------------------ + // We are the leader, and we got a block_id from a proposer, but + // we should probably do something with the justify QC that + // comes with it (which is the _high_qc of the proposer (?)) // - // This makes it work "better", sometimes completing the 3rd phase for an ever-increasing block number, - // but doesn't look like it is doing what we want: - // - update_high_qc(msg.justify); - - + // ------------------------------------------------------------------ if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false) { - //FIXME comment out +#ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", ("id", _id) ("proposal_id", _current_qc.proposal_id) ("quorum_met", _current_qc.quorum_met)); if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", msg.block_id)); - +#endif std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = msg.block_id; state_lock.unlock(); } else { - //FIXME comment out +#ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", ("id", _id) ("proposal_id", _current_qc.proposal_id) ("quorum_met", _current_qc.quorum_met)); - +#endif hs_proposal_message proposal_candidate = new_proposal_candidate( msg.block_id, 0 ); reset_qc(proposal_candidate.proposal_id); - //FIXME comment out +#ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_new_block)", ("id", _id)); - +#endif std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = NULL_BLOCK_ID; _b_leaf = proposal_candidate.proposal_id; @@ -651,34 +660,39 @@ namespace eosio { namespace hotstuff { send_hs_proposal_msg(proposal_candidate); - //FIXME comment out +#ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); +#endif } } void qc_chain::send_hs_proposal_msg(const hs_proposal_message & msg){ - //ilog(" === broadcast_hs_proposal ==="); - //hs_proposal_message_ptr ptr = std::make_shared(msg); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === broadcast_hs_proposal ==="); +#endif _pacemaker->send_hs_proposal_msg(msg, _id); process_proposal(msg); } void qc_chain::send_hs_vote_msg(const hs_vote_message & msg){ - //ilog(" === broadcast_hs_vote ==="); - //hs_vote_message_ptr ptr = std::make_shared(msg); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === broadcast_hs_vote ==="); +#endif _pacemaker->send_hs_vote_msg(msg, _id); process_vote(msg); } void qc_chain::send_hs_new_view_msg(const hs_new_view_message & msg){ - //ilog(" === broadcast_hs_new_view ==="); - //hs_new_view_message_ptr ptr = std::make_shared(msg); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === broadcast_hs_new_view ==="); +#endif _pacemaker->send_hs_new_view_msg(msg, _id); } void qc_chain::send_hs_new_block_msg(const hs_new_block_message & msg){ - //ilog(" === broadcast_hs_new_block ==="); - //hs_new_block_message_ptr ptr = std::make_shared(msg); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === broadcast_hs_new_block ==="); +#endif _pacemaker->send_hs_new_block_msg(msg, _id); } @@ -738,9 +752,9 @@ namespace eosio { namespace hotstuff { // I am the proposer; so this assumes that no additional proposal validation is required. - //FIXME delete +#ifdef QC_CHAIN_TRACE_DEBUG ilog(" === I am a leader-proposer that is proposing a block for itself to lead"); - +#endif // Hardwired consumption by self; no networking. process_new_block( block_candidate ); @@ -749,16 +763,19 @@ namespace eosio { namespace hotstuff { // I'm only a proposer and not the leader; send a new-block-proposal message out to // the network, until it reaches the leader. - //FIXME comment out +#ifdef QC_CHAIN_TRACE_DEBUG ilog(" === broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); - +#endif send_hs_new_block_msg( block_candidate ); } } void qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ - //ilog(" === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); +#endif + // if new high QC is higher than current, update to new if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ @@ -768,7 +785,9 @@ namespace eosio { namespace hotstuff { _b_leaf = _high_qc.proposal_id; state_lock.unlock(); - //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); +#endif } else { const hs_proposal_message *old_high_qc_prop = get_proposal( _high_qc.proposal_id ); const hs_proposal_message *new_high_qc_prop = get_proposal( high_qc.proposal_id ); @@ -783,15 +802,18 @@ namespace eosio { namespace hotstuff { // "The caller does not need this updated on their high_qc structure" -- g //high_qc.quorum_met = true; - //ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); - +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); +#endif std::unique_lock state_lock( _state_mutex ); _high_qc = high_qc; _high_qc.quorum_met = true; _b_leaf = _high_qc.proposal_id; state_lock.unlock(); - //if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); +#endif } } } @@ -814,7 +836,9 @@ namespace eosio { namespace hotstuff { reset_qc(NULL_PROPOSAL_ID); - //if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); +#endif std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = NULL_BLOCK_ID; @@ -904,14 +928,18 @@ namespace eosio { namespace hotstuff { liveness_check = true; safety_check = true; - //if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); +#endif } - //ilog(" === final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", - // ("final_on_qc_check", final_on_qc_check) - // ("monotony_check", monotony_check) - // ("liveness_check", liveness_check) - // ("safety_check", safety_check)); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", + ("final_on_qc_check", final_on_qc_check) + ("monotony_check", monotony_check) + ("liveness_check", liveness_check) + ("safety_check", safety_check)); +#endif bool node_is_safe = final_on_qc_check && monotony_check && (liveness_check || safety_check); if (!node_is_safe) { @@ -985,20 +1013,31 @@ namespace eosio { namespace hotstuff { //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock - //if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height} b_lock height ${b_lock_height}", - // ("id", _id) - // ("_b_lock", _b_lock) - // ("b_1_height", b_1.block_num()) - // ("b_1_phase", b_1.phase_counter) - // ("b_lock_height", b_lock->block_num()) - // ("b_lock_phase", b_lock->phase_counter)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height}", + ("id", _id) + ("_b_lock", _b_lock) + ("b_1_height", b_1.block_num()) + ("b_1_phase", b_1.phase_counter)); + + if ( b_lock != nullptr ) { + if (_log) ilog(" === b_lock height ${b_lock_height} b_lock phase ${b_lock_phase}", + ("b_lock_height", b_lock->block_num()) + ("b_lock_phase", b_lock->phase_counter)); + } +#endif if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ - //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); +#endif std::unique_lock state_lock( _state_mutex ); _b_lock = b_1.proposal_id; //commit phase on b1 state_lock.unlock(); - //if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); + +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); +#endif } if (chain_length < 3) { @@ -1010,11 +1049,13 @@ namespace eosio { namespace hotstuff { hs_proposal_message b = *itr; - //ilog(" === direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", - // ("b_2.parent_id",b_2.parent_id) - // ("b_1.proposal_id", b_1.proposal_id) - // ("b_1.parent_id", b_1.parent_id) - // ("b.proposal_id", b.proposal_id)); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", + ("b_2.parent_id",b_2.parent_id) + ("b_1.proposal_id", b_1.proposal_id) + ("b_1.parent_id", b_1.parent_id) + ("b.proposal_id", b.proposal_id)); +#endif //direct parent relationship verification if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ @@ -1045,7 +1086,9 @@ namespace eosio { namespace hotstuff { commit(b); - //ilog(" === last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); +#endif std::unique_lock state_lock( _state_mutex ); _b_exec = b.proposal_id; //decide phase on b @@ -1092,12 +1135,14 @@ namespace eosio { namespace hotstuff { auto end_itr = _proposal_store.get().upper_bound(cutoff); while (_proposal_store.get().begin() != end_itr){ auto itr = _proposal_store.get().begin(); - //if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", - // ("id", _id) - // ("block_num", itr->block_num()) - // ("phase_counter", itr->phase_counter) - // ("block_id", itr->block_id) - // ("proposal_id", itr->proposal_id)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + ("id", _id) + ("block_num", itr->block_num()) + ("phase_counter", itr->phase_counter) + ("block_id", itr->block_id) + ("proposal_id", itr->proposal_id)); +#endif _proposal_store.get().erase(itr); } #endif @@ -1105,30 +1150,40 @@ namespace eosio { namespace hotstuff { void qc_chain::commit(const hs_proposal_message & proposal){ - //ilog(" === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - // ("block_num", proposal.block_num()) - // ("proposal_id", proposal.proposal_id) - // ("block_id", proposal.block_id) - // ("phase_counter", proposal.phase_counter) - // ("parent_id", proposal.parent_id)); +#ifdef QC_CHAIN_TRACE_DEBUG + ilog(" === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", proposal.block_num()) + ("proposal_id", proposal.proposal_id) + ("block_id", proposal.block_id) + ("phase_counter", proposal.phase_counter) + ("parent_id", proposal.parent_id)); +#endif bool exec_height_check = false; const hs_proposal_message *last_exec_prop = get_proposal( _b_exec ); EOS_ASSERT( last_exec_prop != nullptr || _b_exec == NULL_PROPOSAL_ID, chain_exception, "expected hs_proposal ${id} not found", ("id", _b_exec) ); - //ilog(" === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - // ("block_num", last_exec_prop->block_num()) - // ("proposal_id", last_exec_prop->proposal_id) - // ("block_id", last_exec_prop->block_id) - // ("phase_counter", last_exec_prop->phase_counter) - // ("parent_id", last_exec_prop->parent_id)); - - //ilog(" *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", - // ("proposal_id_1", last_exec_prop->block_num()) - // ("phase_counter_1", last_exec_prop->phase_counter) - // ("proposal_id_2", proposal.block_num()) - // ("phase_counter_2", proposal.phase_counter)); +#ifdef QC_CHAIN_TRACE_DEBUG + if (last_exec_prop != nullptr) { + ilog(" === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + ("block_num", last_exec_prop->block_num()) + ("proposal_id", last_exec_prop->proposal_id) + ("block_id", last_exec_prop->block_id) + ("phase_counter", last_exec_prop->phase_counter) + ("parent_id", last_exec_prop->parent_id)); + + ilog(" *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", + ("proposal_id_1", last_exec_prop->block_num()) + ("phase_counter_1", last_exec_prop->phase_counter) + ("proposal_id_2", proposal.block_num()) + ("phase_counter_2", proposal.phase_counter)); + } else { + ilog(" === _b_exec proposal is null vs proposal ${proposal_id_2} ${phase_counter_2} ", + ("proposal_id_2", proposal.block_num()) + ("phase_counter_2", proposal.phase_counter)); + } +#endif if (_b_exec == NULL_PROPOSAL_ID) exec_height_check = true; @@ -1152,14 +1207,15 @@ namespace eosio { namespace hotstuff { ("block_id", proposal.block_id) ("proposal_id", proposal.proposal_id)); } - - //else { - // if (_errors) ilog(" *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", - // ("id", _id) - // ("block_num", proposal.block_num()) - // ("phase_counter", proposal.phase_counter) - // ("proposal_id", proposal.proposal_id)); - //} + else { +#ifdef QC_CHAIN_TRACE_DEBUG + if (_errors) ilog(" *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", + ("id", _id) + ("block_num", proposal.block_num()) + ("phase_counter", proposal.phase_counter) + ("proposal_id", proposal.proposal_id)); +#endif + } } }} diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 1f9c5cc835..75c583c098 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -846,8 +846,6 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { tpm.beat(); //produce first block - ilog("getting first "); - tpm.dispatch(""); //get the first block from the proposer to the leader tpm.dispatch(""); //send proposal to replicas (prepare on first block) From 005d500e7b9a29325be0fd253710a5fe205f1792 Mon Sep 17 00:00:00 2001 From: fcecin Date: Mon, 8 May 2023 10:21:12 -0300 Subject: [PATCH 030/151] added instant_finality protocol-feature switch --- libraries/chain/controller.cpp | 9 +++++++ .../eosio/chain/protocol_feature_manager.hpp | 1 + libraries/chain/protocol_feature_manager.cpp | 9 +++++++ libraries/hotstuff/chain_pacemaker.cpp | 24 ++++++++++++++++++- .../eosio/hotstuff/chain_pacemaker.hpp | 2 ++ libraries/hotstuff/qc_chain.cpp | 4 ++-- 6 files changed, 46 insertions(+), 3 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 08dbb8390d..3d7073f1b3 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -343,6 +343,7 @@ struct controller_impl { set_activation_handler(); set_activation_handler(); set_activation_handler(); + set_activation_handler(); self.irreversible_block.connect([this](const block_state_ptr& bsp) { get_wasm_interface().current_lib(bsp->block_num); @@ -3861,6 +3862,14 @@ void controller_impl::on_activation +void controller_impl::on_activation() { + db.modify( db.get(), [&]( auto& ps ) { + // FIXME/TODO: host functions to set proposers, leaders, finalizers/validators + } ); +} + /// End of protocol feature activation handlers } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp index 39726485e7..336273864c 100644 --- a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp +++ b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp @@ -36,6 +36,7 @@ enum class builtin_protocol_feature_t : uint32_t { crypto_primitives = 19, get_block_num = 20, aggregate_signatures = 21, + instant_finality = 22, reserved_private_fork_protocol_features = 500000, }; diff --git a/libraries/chain/protocol_feature_manager.cpp b/libraries/chain/protocol_feature_manager.cpp index d799e20184..d077488770 100644 --- a/libraries/chain/protocol_feature_manager.cpp +++ b/libraries/chain/protocol_feature_manager.cpp @@ -267,6 +267,15 @@ Enables new `get_block_num` intrinsic which returns the current block number. // SHA256 hash of the raw message below within the comment delimiters (do not modify message below). /* Builtin protocol feature: AGGREGATE_SIGNATURES +*/ + {} + } ) + ( builtin_protocol_feature_t::instant_finality, builtin_protocol_feature_spec{ + "INSTANT_FINALITY", + fc::variant("bc726a24928ea2d71ba294b70c5c9efc515c1542139bcf9e42f8bc174f2e72ff").as(), + // SHA256 hash of the raw message below within the comment delimiters (do not modify message below). +/* +Builtin protocol feature: INSTANT_FINALITY */ {} } ) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 4394929ff7..f8b23498ec 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -106,8 +106,15 @@ namespace eosio { namespace hotstuff { { } + // Called internally by the chain_pacemaker to decide whether it should do something or not, based on feature activation. + // Only methods called by the outside need to call this; methods called by qc_chain only don't need to check for enable(). + bool chain_pacemaker::enabled() { + return _chain->is_builtin_activated( builtin_protocol_feature_t::instant_finality ); + } + void chain_pacemaker::get_state( finalizer_state & fs ) { - _qc_chain.get_state( fs ); // get_state() takes scare of finer-grained synchronization internally + if (enabled()) + _qc_chain.get_state( fs ); // get_state() takes scare of finer-grained synchronization internally } name chain_pacemaker::get_proposer(){ @@ -224,6 +231,9 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::beat(){ + if (! enabled()) + return; + csc prof("beat"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -252,6 +262,9 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_proposal_msg(const hs_proposal_message & msg){ + if (! enabled()) + return; + csc prof("prop"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -260,6 +273,9 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_vote_msg(const hs_vote_message & msg){ + if (! enabled()) + return; + csc prof("vote"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -268,6 +284,9 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_new_block_msg(const hs_new_block_message & msg){ + if (! enabled()) + return; + csc prof("nblk"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -276,6 +295,9 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_new_view_msg(const hs_new_view_message & msg){ + if (! enabled()) + return; + csc prof("view"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index c4a872a175..50471c59cd 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -45,6 +45,8 @@ namespace eosio { namespace hotstuff { //FIXME/REMOVE: for testing/debugging only name debug_leader_remap(name n); + // Check if consensus upgrade feature is activated + bool enabled(); // This serializes all messages (high-level requests) to the qc_chain core. // For maximum safety, the qc_chain core will only process one request at a time. diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index dabe92191d..5e278a8045 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -730,9 +730,9 @@ namespace eosio { namespace hotstuff { // Invoked when we could perhaps make a proposal to the network (or to ourselves, if we are the leader). void qc_chain::on_beat(){ - // Non-proposing leaders do not care about beat(void), because leaders react to a block proposal + // Non-proposing leaders do not care about on_beat(), because leaders react to a block proposal // which comes from processing an incoming new block message from a proposer instead. - // beat(void) is called by the pacemaker, which decides when it's time to check whether we are + // on_beat() is called by the pacemaker, which decides when it's time to check whether we are // proposers that should check whether as proposers we should propose a new hotstuff block to // the network (or to ourselves, which is faster and doesn't require the bandwidth of an additional // gossip round for a new proposed block). From 53f697d6c34ba1ab1c8c028574c0e783a70971fd Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 17 Aug 2023 20:26:09 -0500 Subject: [PATCH 031/151] Fix merge issues --- libraries/chain/controller.cpp | 1 + libraries/chain/webassembly/crypto.cpp | 16 +++++------ libraries/libfc/test/test_bls.cpp | 5 ++-- plugins/chain_plugin/chain_plugin.cpp | 39 +++++++++++++------------- plugins/net_plugin/net_plugin.cpp | 24 ++++++++-------- 5 files changed, 43 insertions(+), 42 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 92c41e7d35..cda3c89293 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -3876,6 +3876,7 @@ void controller_impl::on_activation( } ); } +template<> void controller_impl::on_activation() { db.modify( db.get(), [&]( auto& ps ) { add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "bls_verify" ); diff --git a/libraries/chain/webassembly/crypto.cpp b/libraries/chain/webassembly/crypto.cpp index 68d3defb6f..6a9e2eadda 100644 --- a/libraries/chain/webassembly/crypto.cpp +++ b/libraries/chain/webassembly/crypto.cpp @@ -417,9 +417,9 @@ namespace eosio { namespace chain { namespace webassembly { fc::crypto::blslib::bls_public_key u_pub; vector u_digest; - datastream s_sig( signature.data(), signature.size() ); - datastream s_pub( pub.data(), pub.size() ); - datastream s_digest( digest.data(), digest.size() ); + fc::datastream s_sig( signature.data(), signature.size() ); + fc::datastream s_pub( pub.data(), pub.size() ); + fc::datastream s_digest( digest.data(), digest.size() ); fc::raw::unpack( s_sig, u_sig ); fc::raw::unpack( s_pub, u_pub ); @@ -438,7 +438,7 @@ namespace eosio { namespace chain { namespace webassembly { vector u_pubkeys; - datastream s_pubkeys( pubkeys.data(), pubkeys.size() ); + fc::datastream s_pubkeys( pubkeys.data(), pubkeys.size() ); fc::raw::unpack( s_pubkeys, u_pubkeys ); @@ -458,7 +458,7 @@ namespace eosio { namespace chain { namespace webassembly { vector u_sigs; - datastream s_sigs( signatures.data(), signatures.size() ); + fc::datastream s_sigs( signatures.data(), signatures.size() ); fc::raw::unpack( s_sigs, u_sigs ); @@ -480,9 +480,9 @@ namespace eosio { namespace chain { namespace webassembly { vector u_pubs; vector> u_digests; - datastream s_sig( signature.data(), signature.size() ); - datastream s_pubs( pubs.data(), pubs.size() ); - datastream s_digests( digests.data(), digests.size() ); + fc::datastream s_sig( signature.data(), signature.size() ); + fc::datastream s_pubs( pubs.data(), pubs.size() ); + fc::datastream s_digests( digests.data(), digests.size() ); fc::raw::unpack( s_sig, u_sig ); fc::raw::unpack( s_pubs, u_pubs ); diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index cb11635e5f..b592a1c50f 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -1,5 +1,4 @@ -#define BOOST_TEST_MODULE bls -#include +#include #include @@ -15,7 +14,7 @@ using std::cout; using namespace fc::crypto::blslib; -BOOST_AUTO_TEST_SUITE(bls) +BOOST_AUTO_TEST_SUITE(bls_test) // can we use BLS stuff? diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index e7ec630eb6..5795c22cfd 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2640,25 +2640,26 @@ read_only::get_consensus_parameters(const get_consensus_parameters_params&, cons read_only::get_finalizer_state_results read_only::get_finalizer_state(const get_finalizer_state_params&, const fc::time_point& deadline ) const { get_finalizer_state_results results; - if ( producer_plug ) { // producer_plug is null when called from chain_plugin_tests.cpp and get_table_tests.cpp - finalizer_state fs; - producer_plug->get_finalizer_state( fs ); - results.chained_mode = fs.chained_mode; - results.b_leaf = fs.b_leaf; - results.b_lock = fs.b_lock; - results.b_exec = fs.b_exec; - results.b_finality_violation = fs.b_finality_violation; - results.block_exec = fs.block_exec; - results.pending_proposal_block = fs.pending_proposal_block; - results.v_height = fs.v_height; - results.high_qc = fs.high_qc; - results.current_qc = fs.current_qc; - results.schedule = fs.schedule; - for (auto proposal: fs.proposals) { - chain::hs_proposal_message & p = proposal.second; - results.proposals.push_back( hs_complete_proposal_message( p ) ); - } - } + // TODO: move to producer_plugin +// if ( producer_plug ) { // producer_plug is null when called from chain_plugin_tests.cpp and get_table_tests.cpp +// finalizer_state fs; +// producer_plug->get_finalizer_state( fs ); +// results.chained_mode = fs.chained_mode; +// results.b_leaf = fs.b_leaf; +// results.b_lock = fs.b_lock; +// results.b_exec = fs.b_exec; +// results.b_finality_violation = fs.b_finality_violation; +// results.block_exec = fs.block_exec; +// results.pending_proposal_block = fs.pending_proposal_block; +// results.v_height = fs.v_height; +// results.high_qc = fs.high_qc; +// results.current_qc = fs.current_qc; +// results.schedule = fs.schedule; +// for (auto proposal: fs.proposals) { +// chain::hs_proposal_message & p = proposal.second; +// results.proposals.push_back( hs_complete_proposal_message( p ) ); +// } +// } return results; } diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index aebf642710..94860a39b1 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -2561,9 +2561,9 @@ namespace eosio { } void dispatch_manager::bcast_hs_proposal_msg(const hs_proposal_message_ptr& msg) { - if( my_impl->sync_master->syncing_with_peer() ) return; + if( my_impl->sync_master->syncing_from_peer() ) return; hs_proposal_message & msg_val = *(msg.get()); - for_each_block_connection( [this, &msg_val]( auto& cp ) { + my_impl->connections.for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; cp->strand.post( [this, cp, msg_val]() { if (cp->protocol_version >= proto_instant_finality) @@ -2574,9 +2574,9 @@ namespace eosio { } void dispatch_manager::bcast_hs_vote_msg(const hs_vote_message_ptr& msg) { - if( my_impl->sync_master->syncing_with_peer() ) return; + if( my_impl->sync_master->syncing_from_peer() ) return; hs_vote_message & msg_val = *(msg.get()); - for_each_block_connection( [this, &msg_val]( auto& cp ) { + my_impl->connections.for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; cp->strand.post( [this, cp, msg_val]() { if (cp->protocol_version >= proto_instant_finality) @@ -2587,9 +2587,9 @@ namespace eosio { } void dispatch_manager::bcast_hs_new_block_msg(const hs_new_block_message_ptr& msg) { - if( my_impl->sync_master->syncing_with_peer() ) return; + if( my_impl->sync_master->syncing_from_peer() ) return; hs_new_block_message & msg_val = *(msg.get()); - for_each_block_connection( [this, &msg_val]( auto& cp ) { + my_impl->connections.for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; cp->strand.post( [this, cp, msg_val]() { if (cp->protocol_version >= proto_instant_finality) @@ -2600,9 +2600,9 @@ namespace eosio { } void dispatch_manager::bcast_hs_new_view_msg(const hs_new_view_message_ptr& msg) { - if( my_impl->sync_master->syncing_with_peer() ) return; + if( my_impl->sync_master->syncing_from_peer() ) return; hs_new_view_message & msg_val = *(msg.get()); - for_each_block_connection( [this, &msg_val]( auto& cp ) { + my_impl->connections.for_each_block_connection( [this, &msg_val]( auto& cp ) { if( !cp->current() ) return true; cp->strand.post( [this, cp, msg_val]() { if (cp->protocol_version >= proto_instant_finality) @@ -4349,16 +4349,16 @@ namespace eosio { my->on_irreversible_block( s ); } ); - cc.new_hs_proposal_message.connect( [my = my]( const hs_proposal_message_ptr& s ) { + cc.new_hs_proposal_message.connect( [my = shared_from_this()]( const hs_proposal_message_ptr& s ) { my->on_hs_proposal_message( s ); } ); - cc.new_hs_vote_message.connect( [my = my]( const hs_vote_message_ptr& s ) { + cc.new_hs_vote_message.connect( [my = shared_from_this()]( const hs_vote_message_ptr& s ) { my->on_hs_vote_message( s ); } ); - cc.new_hs_new_view_message.connect( [my = my]( const hs_new_view_message_ptr& s ) { + cc.new_hs_new_view_message.connect( [my = shared_from_this()]( const hs_new_view_message_ptr& s ) { my->on_hs_new_view_message( s ); } ); - cc.new_hs_new_block_message.connect( [my = my]( const hs_new_block_message_ptr& s ) { + cc.new_hs_new_block_message.connect( [my = shared_from_this()]( const hs_new_block_message_ptr& s ) { my->on_hs_new_block_message( s ); } ); From 5e67e262be62d1ab1efdf310701bb181635cb20e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 17 Aug 2023 20:27:34 -0500 Subject: [PATCH 032/151] Switch to bls12_381 library --- libraries/chain/abi_serializer.cpp | 3 - .../chain/include/eosio/chain/hotstuff.hpp | 2 - libraries/chain/include/eosio/chain/types.hpp | 4 -- libraries/chain/webassembly/crypto.cpp | 53 +++++++++-------- .../include/fc/crypto/bls_private_key.hpp | 4 +- .../include/fc/crypto/bls_public_key.hpp | 8 +-- .../libfc/include/fc/crypto/bls_signature.hpp | 12 ++-- .../libfc/src/crypto/bls_private_key.cpp | 18 +++--- libraries/libfc/src/crypto/bls_public_key.cpp | 16 ++--- libraries/libfc/src/crypto/bls_signature.cpp | 22 +++---- libraries/libfc/src/crypto/bls_utils.cpp | 58 ++++++++----------- 11 files changed, 97 insertions(+), 103 deletions(-) diff --git a/libraries/chain/abi_serializer.cpp b/libraries/chain/abi_serializer.cpp index fdc1cfee1c..0e6232b8af 100644 --- a/libraries/chain/abi_serializer.cpp +++ b/libraries/chain/abi_serializer.cpp @@ -123,9 +123,6 @@ namespace eosio { namespace chain { built_in_types.emplace("public_key", pack_unpack_deadline()); built_in_types.emplace("signature", pack_unpack_deadline()); - built_in_types.emplace("bls_public_key", pack_unpack_deadline()); - built_in_types.emplace("bls_signature", pack_unpack_deadline()); - built_in_types.emplace("symbol", pack_unpack()); built_in_types.emplace("symbol_code", pack_unpack()); built_in_types.emplace("asset", pack_unpack()); diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index a29b87e3f5..08135162ec 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -40,8 +40,6 @@ namespace eosio { namespace chain { fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal name finalizer; fc::crypto::blslib::bls_signature sig; - - hs_vote_message() = default; }; struct hs_proposal_message { diff --git a/libraries/chain/include/eosio/chain/types.hpp b/libraries/chain/include/eosio/chain/types.hpp index 5ca4f62b07..0d12de8158 100644 --- a/libraries/chain/include/eosio/chain/types.hpp +++ b/libraries/chain/include/eosio/chain/types.hpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -78,9 +77,6 @@ namespace eosio::chain { using private_key_type = fc::crypto::private_key; using signature_type = fc::crypto::signature; - using bls_public_key_type = fc::crypto::blslib::bls_public_key; - using bls_signature_type = fc::crypto::blslib::bls_signature; - // configurable boost deque (for boost >= 1.71) performs much better than std::deque in our use cases using block_1024_option_t = boost::container::deque_options< boost::container::block_size<1024u> >::type; template diff --git a/libraries/chain/webassembly/crypto.cpp b/libraries/chain/webassembly/crypto.cpp index 6a9e2eadda..ff8d6ead99 100644 --- a/libraries/chain/webassembly/crypto.cpp +++ b/libraries/chain/webassembly/crypto.cpp @@ -421,9 +421,10 @@ namespace eosio { namespace chain { namespace webassembly { fc::datastream s_pub( pub.data(), pub.size() ); fc::datastream s_digest( digest.data(), digest.size() ); - fc::raw::unpack( s_sig, u_sig ); - fc::raw::unpack( s_pub, u_pub ); - fc::raw::unpack( s_digest, u_digest ); + // TODO determine how we want to serialize signature +// fc::raw::unpack( s_sig, u_sig ); +// fc::raw::unpack( s_pub, u_pub ); +// fc::raw::unpack( s_digest, u_digest ); std::cerr << u_pub.to_string() << "\n"; std::cerr << u_sig.to_string() << "\n"; @@ -440,18 +441,19 @@ namespace eosio { namespace chain { namespace webassembly { fc::datastream s_pubkeys( pubkeys.data(), pubkeys.size() ); - fc::raw::unpack( s_pubkeys, u_pubkeys ); + // TODO determine how we want to serialize bls_public_key + //fc::raw::unpack( s_pubkeys, u_pubkeys ); fc::crypto::blslib::bls_public_key agg_pubkey = fc::crypto::blslib::aggregate(u_pubkeys); - auto packed = fc::raw::pack(agg_pubkey); - - auto copy_size = std::min(aggregate.size(), packed.size()); - - std::memcpy(aggregate.data(), packed.data(), copy_size); - - return packed.size(); - +// auto packed = fc::raw::pack(agg_pubkey); +// +// auto copy_size = std::min(aggregate.size(), packed.size()); +// +// std::memcpy(aggregate.data(), packed.data(), copy_size); +// +// return packed.size(); + return 0; } int32_t interface::bls_aggregate_sigs( span signatures, span aggregate) const { @@ -460,18 +462,19 @@ namespace eosio { namespace chain { namespace webassembly { fc::datastream s_sigs( signatures.data(), signatures.size() ); - fc::raw::unpack( s_sigs, u_sigs ); +// fc::raw::unpack( s_sigs, u_sigs ); fc::crypto::blslib::bls_signature agg_sig = fc::crypto::blslib::aggregate(u_sigs); - auto packed = fc::raw::pack(agg_sig); - - auto copy_size = std::min(aggregate.size(), packed.size()); - - std::memcpy(aggregate.data(), packed.data(), copy_size); - - return packed.size(); - + // TODO determine how we want to serialize signature +// auto packed = fc::raw::pack(agg_sig); +// +// auto copy_size = std::min(aggregate.size(), packed.size()); +// +// std::memcpy(aggregate.data(), packed.data(), copy_size); +// +// return packed.size(); + return 0; } bool interface::bls_aggregate_verify( span signature, span digests, span pubs) const { @@ -484,9 +487,11 @@ namespace eosio { namespace chain { namespace webassembly { fc::datastream s_pubs( pubs.data(), pubs.size() ); fc::datastream s_digests( digests.data(), digests.size() ); - fc::raw::unpack( s_sig, u_sig ); - fc::raw::unpack( s_pubs, u_pubs ); - fc::raw::unpack( s_digests, u_digests ); + // TODO determine how we want to serialize signature + // TODO determine how we want to serialize bls_public_key +// fc::raw::unpack( s_sig, u_sig ); +// fc::raw::unpack( s_pubs, u_pubs ); +// fc::raw::unpack( s_digests, u_digests ); bool result = fc::crypto::blslib::aggregate_verify(u_pubs, u_digests, u_sig); diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 37b17ef343..3509217b4d 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -6,11 +6,11 @@ #include #include #include -#include +#include namespace fc { namespace crypto { namespace blslib { - using namespace bls; + using namespace bls12_381; namespace config { constexpr const char* bls_private_key_base_prefix = "PVT"; diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index 5b98eccbfe..b805252de3 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -6,7 +6,7 @@ #include #include #include -//#include +#include namespace fc { namespace crypto { namespace blslib { @@ -28,7 +28,7 @@ namespace fc { namespace crypto { namespace blslib { bls_public_key( const bls_public_key& ) = default; bls_public_key& operator= (const bls_public_key& ) = default; - bls_public_key( std::vector pkey ){ + bls_public_key( bls12_381::g1 pkey ){ _pkey = pkey; } @@ -54,8 +54,7 @@ namespace fc { namespace crypto { namespace blslib { std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; //storage_type _storage; - - std::vector _pkey; + bls12_381::g1 _pkey; private: @@ -76,4 +75,5 @@ namespace fc { void from_variant(const variant& var, crypto::blslib::bls_public_key& vo); } // namespace fc +FC_REFLECT(bls12_381::g1, (x)(y)(z)) FC_REFLECT(fc::crypto::blslib::bls_public_key, (_pkey) ) diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index 88f1483554..3c07333cbf 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -6,7 +6,8 @@ #include #include #include -//#include +#include + namespace fc { namespace crypto { namespace blslib { @@ -27,7 +28,7 @@ namespace fc { namespace crypto { namespace blslib { bls_signature( const bls_signature& ) = default; bls_signature& operator= (const bls_signature& ) = default; - bls_signature( std::vector sig ){ + bls_signature( bls12_381::g2 sig ){ _sig = sig; } @@ -39,12 +40,12 @@ namespace fc { namespace crypto { namespace blslib { explicit bls_signature(const string& base58str); std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; - size_t which() const; +// size_t which() const; size_t variable_size() const; - std::vector _sig; + bls12_381::g2 _sig; private: @@ -83,4 +84,7 @@ namespace std { }; } // std +FC_REFLECT(bls12_381::fp, (d)) +FC_REFLECT(bls12_381::fp2, (c0)(c1)) +FC_REFLECT(bls12_381::g2, (x)(y)(z)) FC_REFLECT(fc::crypto::blslib::bls_signature, (_sig) ) diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index 009b771ac7..b54d995326 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -7,19 +7,17 @@ namespace fc { namespace crypto { namespace blslib { using namespace std; bls_public_key bls_private_key::get_public_key() const - { - G1Element pk = AugSchemeMPL().KeyGen(_seed).GetG1Element(); - - return bls_public_key(pk.Serialize()); + { + auto sk = bls12_381::secret_key(_seed); + g1 pk = bls12_381::public_key(sk); + return bls_public_key(pk); } bls_signature bls_private_key::sign( vector message ) const - { - - PrivateKey sk = AugSchemeMPL().KeyGen(_seed); - - G2Element s = PopSchemeMPL().Sign(sk, message); - return bls_signature(s.Serialize()); + { + std::array sk = secret_key(_seed); + g2 sig = bls12_381::sign(sk, message); + return bls_signature(sig); } /*struct public_key_visitor : visitor { diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index b72f71ded5..4d4c888cf5 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -28,7 +28,7 @@ namespace fc { namespace crypto { namespace blslib { return _storage.index(); }*/ - static vector parse_base58(const std::string& base58str) + static bls12_381::g1 parse_base58(const std::string& base58str) { constexpr auto prefix = config::bls_public_key_base_prefix; @@ -38,11 +38,12 @@ namespace fc { namespace crypto { namespace blslib { std::vector v1 = fc::from_base58(data_str); - std::vector v2; - std::copy(v1.begin(), v1.end(), std::back_inserter(v2)); - - return v2; - + FC_ASSERT(v1.size() == 48); + std::array v2; + std::copy(v1.begin(), v1.end(), v2.begin()); + std::optional g1 = bls12_381::g1::fromCompressedBytesBE(v2); + FC_ASSERT(g1); + return *g1; } bls_public_key::bls_public_key(const std::string& base58str) @@ -59,7 +60,8 @@ namespace fc { namespace crypto { namespace blslib { std::string bls_public_key::to_string(const fc::yield_function_t& yield)const { std::vector v2; - std::copy(_pkey.begin(), _pkey.end(), std::back_inserter(v2)); + std::array bytes = _pkey.toCompressedBytesBE(); + std::copy(bytes.begin(), bytes.end(), std::back_inserter(v2)); std::string data_str = fc::to_base58(v2, yield); diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 78c82de1d1..6e2c0732a8 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -17,7 +17,7 @@ namespace fc { namespace crypto { namespace blslib { }*/ }; - static vector sig_parse_base58(const std::string& base58str) + static bls12_381::g2 sig_parse_base58(const std::string& base58str) { try { @@ -28,20 +28,21 @@ namespace fc { namespace crypto { namespace blslib { std::vector v1 = fc::from_base58(data_str); - std::vector v2; - std::copy(v1.begin(), v1.end(), std::back_inserter(v2)); - - return v2; - + FC_ASSERT(v1.size() == 96); + std::array v2; + std::copy(v1.begin(), v1.end(), v2.begin()); + std::optional g2 = bls12_381::g2::fromCompressedBytesBE(v2); + FC_ASSERT(g2); + return *g2; } FC_RETHROW_EXCEPTIONS( warn, "error parsing bls_signature", ("str", base58str ) ) } bls_signature::bls_signature(const std::string& base58str) :_sig(sig_parse_base58(base58str)) {} - size_t bls_signature::which() const { - //return _storage.index(); - } +// size_t bls_signature::which() const { +// //return _storage.index(); +// } //template struct overloaded : Ts... { using Ts::operator()...; }; @@ -62,7 +63,8 @@ namespace fc { namespace crypto { namespace blslib { { std::vector v2; - std::copy(_sig.begin(), _sig.end(), std::back_inserter(v2)); + std::array bytes = _sig.toCompressedBytesBE(); + std::copy(bytes.begin(), bytes.end(), std::back_inserter(v2)); std::string data_str = fc::to_base58(v2, yield); diff --git a/libraries/libfc/src/crypto/bls_utils.cpp b/libraries/libfc/src/crypto/bls_utils.cpp index 3a36666c91..b9aae6586c 100644 --- a/libraries/libfc/src/crypto/bls_utils.cpp +++ b/libraries/libfc/src/crypto/bls_utils.cpp @@ -14,48 +14,40 @@ namespace fc { namespace crypto { namespace blslib { } - bool verify( const bls_public_key &pubkey, - const vector &message, - const bls_signature &signature){ - - return PopSchemeMPL().Verify(pubkey._pkey, message, signature._sig); - + bool verify(const bls_public_key &pubkey, + const vector &message, + const bls_signature &signature) { + return bls12_381::verify(pubkey._pkey, message, signature._sig); }; - bls_public_key aggregate( const vector &keys){ - - G1Element aggKey; - - for (size_t i = 0 ; i < keys.size(); i++){ - aggKey += G1Element::FromByteVector(keys[i]._pkey); + bls_public_key aggregate(const vector& keys) { + std::vector ks; + ks.reserve(keys.size()); + for( const auto& k : keys ) { + ks.push_back(k._pkey); } - - return bls_public_key(aggKey.Serialize()); - + bls12_381::g1 agg = bls12_381::aggregate_public_keys(ks); + return bls_public_key(agg); }; - bls_signature aggregate( const vector &signatures){ - - vector> v_sigs; - - for (size_t i = 0 ; i < signatures.size(); i++) - v_sigs.push_back(signatures[i]._sig); - - return bls_signature(PopSchemeMPL().Aggregate(v_sigs)); + bls_signature aggregate(const vector& signatures) { + std::vector sigs; + sigs.reserve(signatures.size()); + bls12_381::g2 agg = bls12_381::aggregate_signatures(sigs); + return bls_signature{agg}; }; - bool aggregate_verify( const vector &pubkeys, - const vector> &messages, - const bls_signature &signature){ - - vector> v_pubkeys; - - for (size_t i = 0 ; i < pubkeys.size(); i++) - v_pubkeys.push_back(pubkeys[i]._pkey); - - return PopSchemeMPL().AggregateVerify(v_pubkeys, messages, signature._sig); + bool aggregate_verify(const vector& pubkeys, + const vector>& messages, + const bls_signature& signature) { + std::vector ks; + ks.reserve(pubkeys.size()); + for( const auto& k : pubkeys ) { + ks.push_back(k._pkey); + } + return bls12_381::aggregate_verify(ks, messages, signature._sig); }; } } } // fc::crypto::blslib From 129e62a24cec9eb8227b77e18792caf8e247ae2c Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 17 Aug 2023 20:32:16 -0500 Subject: [PATCH 033/151] Remove bls-signatures subdirectory --- libraries/libfc/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/libfc/CMakeLists.txt b/libraries/libfc/CMakeLists.txt index e8d2678e5b..6d99ab9f5a 100644 --- a/libraries/libfc/CMakeLists.txt +++ b/libraries/libfc/CMakeLists.txt @@ -2,8 +2,6 @@ add_subdirectory( secp256k1 ) add_subdirectory( libraries/bn256/src ) add_subdirectory( libraries/bls12-381 ) -add_subdirectory( libraries/bls-signatures ) - set(CMAKE_THREAD_PREFER_PTHREAD TRUE) set(THREADS_PREFER_PTHREAD_FLAG TRUE) find_package(Threads) From 57be9e85d4ee8fe6d7a57ed77a8f22671a2956c3 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 06:29:46 -0500 Subject: [PATCH 034/151] Remove bls-signatures subdirectory --- libraries/libfc/libraries/bls-signatures | 1 - 1 file changed, 1 deletion(-) delete mode 160000 libraries/libfc/libraries/bls-signatures diff --git a/libraries/libfc/libraries/bls-signatures b/libraries/libfc/libraries/bls-signatures deleted file mode 160000 index 3980ffea61..0000000000 --- a/libraries/libfc/libraries/bls-signatures +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3980ffea618160a6b8ef0edc427721a796de957f From 0c1a5ade15bdcfdc583279fa78ac185837fc471e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 07:25:17 -0500 Subject: [PATCH 035/151] Move test_sig_single to the test that uses it --- libraries/libfc/test/test_bls.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index b592a1c50f..4824bcc626 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -40,8 +40,6 @@ fc::sha256 message_3 = fc::sha256("1097cf48a15ba1c618237d3d79f3c684c031a9844c27e std::vector message_4 = {143,10,193,195,104,126,124,222,124,64,177,164,240,234,110,18,142,236,191,66,223,47,235,248,75,9,172,99,178,26,239,78}; -bls_signature test_sig_single = bls_signature("SIG_BLS_23PuSu1B72cPe6wxGkKjAaaZqA1Ph79zSoW7omsKKUrnprbA3cJCJVhT48QKUG6ofjYTTg4BA4TrVENWyrxjTomwLX6TGdVg2RYhKH7Kk9X23K5ohuhKQcWQ6AwJJGVSbSp4"); - //test a single key signature + verification BOOST_AUTO_TEST_CASE(bls_sig_verif) try { @@ -121,6 +119,7 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_hotstuff_types) try { //test a aggregate signature from string BOOST_AUTO_TEST_CASE(bls_sig_verif_string_multi) try { + bls_signature test_sig_single = bls_signature("SIG_BLS_23PuSu1B72cPe6wxGkKjAaaZqA1Ph79zSoW7omsKKUrnprbA3cJCJVhT48QKUG6ofjYTTg4BA4TrVENWyrxjTomwLX6TGdVg2RYhKH7Kk9X23K5ohuhKQcWQ6AwJJGVSbSp4"); bls_private_key sk = bls_private_key(seed_1); bls_public_key agg_key = sk.get_public_key(); From 2a949ba6744adf873ba294618db0d4f20146e95b Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 07:37:27 -0500 Subject: [PATCH 036/151] Fix aggregate of signatures --- libraries/libfc/src/crypto/bls_utils.cpp | 109 ++++++++++++----------- 1 file changed, 56 insertions(+), 53 deletions(-) diff --git a/libraries/libfc/src/crypto/bls_utils.cpp b/libraries/libfc/src/crypto/bls_utils.cpp index b9aae6586c..a3e228c11d 100644 --- a/libraries/libfc/src/crypto/bls_utils.cpp +++ b/libraries/libfc/src/crypto/bls_utils.cpp @@ -1,53 +1,56 @@ -#include - -namespace fc { namespace crypto { namespace blslib { - - bls_private_key generate() { - - char* r = (char*) malloc(32); - - rand_bytes(r, 32); - - vector v(r, r+32); - - return bls_private_key(v); - - } - - bool verify(const bls_public_key &pubkey, - const vector &message, - const bls_signature &signature) { - return bls12_381::verify(pubkey._pkey, message, signature._sig); - }; - - bls_public_key aggregate(const vector& keys) { - std::vector ks; - ks.reserve(keys.size()); - for( const auto& k : keys ) { - ks.push_back(k._pkey); - } - bls12_381::g1 agg = bls12_381::aggregate_public_keys(ks); - return bls_public_key(agg); - }; - - bls_signature aggregate(const vector& signatures) { - std::vector sigs; - sigs.reserve(signatures.size()); - - bls12_381::g2 agg = bls12_381::aggregate_signatures(sigs); - return bls_signature{agg}; - }; - - bool aggregate_verify(const vector& pubkeys, - const vector>& messages, - const bls_signature& signature) { - std::vector ks; - ks.reserve(pubkeys.size()); - for( const auto& k : pubkeys ) { - ks.push_back(k._pkey); - } - - return bls12_381::aggregate_verify(ks, messages, signature._sig); - }; - -} } } // fc::crypto::blslib +#include + +namespace fc { namespace crypto { namespace blslib { + + bls_private_key generate() { + + char* r = (char*) malloc(32); + + rand_bytes(r, 32); + + vector v(r, r+32); + + return bls_private_key(v); + + } + + bool verify(const bls_public_key& pubkey, + const vector& message, + const bls_signature& signature) { + return bls12_381::verify(pubkey._pkey, message, signature._sig); + }; + + bls_public_key aggregate(const vector& keys) { + std::vector ks; + ks.reserve(keys.size()); + for( const auto& k : keys ) { + ks.push_back(k._pkey); + } + bls12_381::g1 agg = bls12_381::aggregate_public_keys(ks); + return bls_public_key(agg); + }; + + bls_signature aggregate(const vector& signatures) { + std::vector sigs; + sigs.reserve(signatures.size()); + for( const auto& s : signatures ) { + sigs.push_back(s._sig); + } + + bls12_381::g2 agg = bls12_381::aggregate_signatures(sigs); + return bls_signature{agg}; + }; + + bool aggregate_verify(const vector& pubkeys, + const vector>& messages, + const bls_signature& signature) { + std::vector ks; + ks.reserve(pubkeys.size()); + for( const auto& k : pubkeys ) { + ks.push_back(k._pkey); + } + + return bls12_381::aggregate_verify(ks, messages, signature._sig); + }; + +} } } // fc::crypto::blslib From 8f1f3f187aecbbd40fb419d30f68d438557c8a97 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 07:52:41 -0500 Subject: [PATCH 037/151] Fix memory leak in generate() --- .../include/fc/crypto/bls_private_key.hpp | 11 +-- .../libfc/include/fc/crypto/bls_utils.hpp | 71 ++------------ .../libfc/src/crypto/bls_private_key.cpp | 94 ++++++++++--------- libraries/libfc/src/crypto/bls_utils.cpp | 16 +--- libraries/libfc/test/test_bls.cpp | 2 +- 5 files changed, 64 insertions(+), 130 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 3509217b4d..571d1b9d51 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -36,16 +36,7 @@ namespace fc { namespace crypto { namespace blslib { std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; - static bls_private_key generate() { - - char* r = (char*) malloc(32); - - rand_bytes(r, 32); - - vector v(r, r+32); - - return bls_private_key(v); - } + static bls_private_key generate(); /* template< typename KeyType = r1::private_key_shim > static bls_private_key generate_r1() { diff --git a/libraries/libfc/include/fc/crypto/bls_utils.hpp b/libraries/libfc/include/fc/crypto/bls_utils.hpp index 5cb32c674a..1f59aee7ff 100644 --- a/libraries/libfc/include/fc/crypto/bls_utils.hpp +++ b/libraries/libfc/include/fc/crypto/bls_utils.hpp @@ -2,70 +2,19 @@ #include #include #include -#include -//#include -namespace fc { namespace crypto { namespace blslib { +namespace fc::crypto::blslib { - //static - bls_private_key generate();/* { + bool verify(const bls_public_key& pubkey, + const vector& message, + const bls_signature& signature); - char* r = (char*) malloc(32); + bls_public_key aggregate(const vector& keys); - rand_bytes(r, 32); + bls_signature aggregate(const vector& signatures); - vector v(r, r+32); + bool aggregate_verify(const vector& pubkeys, + const vector>& messages, + const bls_signature& signature); - return bls_private_key(v); - - }*/ - - //static - bool verify( const bls_public_key &pubkey, - const vector &message, - const bls_signature &signature);/*{ - - return PopSchemeMPL().Verify(pubkey._pkey, message, signature._sig); - - };*/ - - //static - bls_public_key aggregate( const vector &keys);/*{ - - G1Element aggKey; - - for (size_t i = 0 ; i < keys.size(); i++){ - aggKey += G1Element::FromByteVector(keys[i]._pkey); - } - - return bls_public_key(aggKey.Serialize()); - - };*/ - - //static - bls_signature aggregate( const vector &signatures);/*{ - - vector> v_sigs; - - for (size_t i = 0 ; i < signatures.size(); i++) - v_sigs.push_back(signatures[i]._sig); - - return bls_signature(PopSchemeMPL().Aggregate(v_sigs)); - - };*/ - - //static - bool aggregate_verify( const vector &pubkeys, - const vector> &messages, - const bls_signature &signature);/*{ - - vector> v_pubkeys; - - for (size_t i = 0 ; i < pubkeys.size(); i++) - v_pubkeys.push_back(pubkeys[i]._pkey); - - return PopSchemeMPL().AggregateVerify(v_pubkeys, messages, signature._sig); - - };*/ - -} } } // fc::crypto::blslib +} // fc::crypto::blslib diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index b54d995326..3591a005f9 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -20,58 +20,64 @@ namespace fc { namespace crypto { namespace blslib { return bls_signature(sig); } - /*struct public_key_visitor : visitor { - template - bls_public_key::storage_type operator()(const KeyType& key) const - { - //return bls_public_key::storage_type(key.get_public_key()); - } - }; - - struct sign_visitor : visitor { - sign_visitor( const sha256& digest, bool require_canonical ) - :_digest(digest) - ,_require_canonical(require_canonical) - {} + bls_private_key bls_private_key::generate() { + std::vector v(32); + rand_bytes(reinterpret_cast(&v[0]), 32); + return bls_private_key(v); + } - template - bls_signature::storage_type operator()(const KeyType& key) const + /*struct public_key_visitor : visitor { + template + bls_public_key::storage_type operator()(const KeyType& key) const + { + //return bls_public_key::storage_type(key.get_public_key()); + } + }; + + struct sign_visitor : visitor { + sign_visitor( const sha256& digest, bool require_canonical ) + :_digest(digest) + ,_require_canonical(require_canonical) + {} + + template + bls_signature::storage_type operator()(const KeyType& key) const + { + return bls_signature::storage_type(key.sign(_digest, _require_canonical)); + } + + const sha256& _digest; + bool _require_canonical; + }; + + bls_signature bls_private_key::sign( vector message ) const { - return bls_signature::storage_type(key.sign(_digest, _require_canonical)); + //return bls_signature(std::visit(sign_visitor(digest, require_canonical), _seed)); } - const sha256& _digest; - bool _require_canonical; - }; - - bls_signature bls_private_key::sign( vector message ) const - { - //return bls_signature(std::visit(sign_visitor(digest, require_canonical), _seed)); - } - - struct generate_shared_secret_visitor : visitor { - generate_shared_secret_visitor( const bls_public_key::storage_type& pub_storage ) - :_pub_storage(pub_storage) - {} + struct generate_shared_secret_visitor : visitor { + generate_shared_secret_visitor( const bls_public_key::storage_type& pub_storage ) + :_pub_storage(pub_storage) + {} - template - sha512 operator()(const KeyType& key) const - { - using PublicKeyType = typename KeyType::public_key_type; - return key.generate_shared_secret(std::template get(_pub_storage)); - } + template + sha512 operator()(const KeyType& key) const + { + using PublicKeyType = typename KeyType::public_key_type; + return key.generate_shared_secret(std::template get(_pub_storage)); + } - const bls_public_key::storage_type& _pub_storage; - }; + const bls_public_key::storage_type& _pub_storage; + }; - sha512 bls_private_key::generate_shared_secret( const bls_public_key& pub ) const + sha512 bls_private_key::generate_shared_secret( const bls_public_key& pub ) const - template - string to_wif( const Data& secret, const fc::yield_function_t& yield ) - { - { - return std::visit(generate_shared_secret_visitor(pub._storage), _seed); - }*/ + template + string to_wif( const Data& secret, const fc::yield_function_t& yield ) + { + { + return std::visit(generate_shared_secret_visitor(pub._storage), _seed); + }*/ /* const size_t size_of_data_to_hash = sizeof(typename Data::data_type) + 1; const size_t size_of_hash_bytes = 4; char data[size_of_data_to_hash + size_of_hash_bytes]; diff --git a/libraries/libfc/src/crypto/bls_utils.cpp b/libraries/libfc/src/crypto/bls_utils.cpp index a3e228c11d..0da768c3b7 100644 --- a/libraries/libfc/src/crypto/bls_utils.cpp +++ b/libraries/libfc/src/crypto/bls_utils.cpp @@ -1,18 +1,6 @@ #include -namespace fc { namespace crypto { namespace blslib { - - bls_private_key generate() { - - char* r = (char*) malloc(32); - - rand_bytes(r, 32); - - vector v(r, r+32); - - return bls_private_key(v); - - } +namespace fc::crypto::blslib { bool verify(const bls_public_key& pubkey, const vector& message, @@ -53,4 +41,4 @@ namespace fc { namespace crypto { namespace blslib { return bls12_381::aggregate_verify(ks, messages, signature._sig); }; -} } } // fc::crypto::blslib +} // fc::crypto::blslib diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 4824bcc626..6ba57e986e 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -243,7 +243,7 @@ BOOST_AUTO_TEST_CASE(bls_agg_tree_verif) try { //test random key generation, signature + verification BOOST_AUTO_TEST_CASE(bls_key_gen) try { - bls_private_key sk = generate(); + bls_private_key sk = bls_private_key::generate(); bls_public_key pk = sk.get_public_key(); bls_signature signature = sk.sign(message_1); From 6bb77ba9929aad7b22e7a31190e5975051a03b07 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 07:58:32 -0500 Subject: [PATCH 038/151] Uncomment serialization now that it is implemented --- libraries/chain/webassembly/crypto.cpp | 47 ++++++++++++-------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/libraries/chain/webassembly/crypto.cpp b/libraries/chain/webassembly/crypto.cpp index ff8d6ead99..78107a6564 100644 --- a/libraries/chain/webassembly/crypto.cpp +++ b/libraries/chain/webassembly/crypto.cpp @@ -422,9 +422,9 @@ namespace eosio { namespace chain { namespace webassembly { fc::datastream s_digest( digest.data(), digest.size() ); // TODO determine how we want to serialize signature -// fc::raw::unpack( s_sig, u_sig ); -// fc::raw::unpack( s_pub, u_pub ); -// fc::raw::unpack( s_digest, u_digest ); + fc::raw::unpack( s_sig, u_sig ); + fc::raw::unpack( s_pub, u_pub ); + fc::raw::unpack( s_digest, u_digest ); std::cerr << u_pub.to_string() << "\n"; std::cerr << u_sig.to_string() << "\n"; @@ -432,7 +432,6 @@ namespace eosio { namespace chain { namespace webassembly { bool result = fc::crypto::blslib::verify(u_pub, u_digest, u_sig); return result; - } int32_t interface::bls_aggregate_pubkeys( span pubkeys, span aggregate) const { @@ -442,18 +441,17 @@ namespace eosio { namespace chain { namespace webassembly { fc::datastream s_pubkeys( pubkeys.data(), pubkeys.size() ); // TODO determine how we want to serialize bls_public_key - //fc::raw::unpack( s_pubkeys, u_pubkeys ); + fc::raw::unpack( s_pubkeys, u_pubkeys ); fc::crypto::blslib::bls_public_key agg_pubkey = fc::crypto::blslib::aggregate(u_pubkeys); -// auto packed = fc::raw::pack(agg_pubkey); -// -// auto copy_size = std::min(aggregate.size(), packed.size()); -// -// std::memcpy(aggregate.data(), packed.data(), copy_size); -// -// return packed.size(); - return 0; + auto packed = fc::raw::pack(agg_pubkey); + + auto copy_size = std::min(aggregate.size(), packed.size()); + + std::memcpy(aggregate.data(), packed.data(), copy_size); + + return packed.size(); } int32_t interface::bls_aggregate_sigs( span signatures, span aggregate) const { @@ -462,19 +460,18 @@ namespace eosio { namespace chain { namespace webassembly { fc::datastream s_sigs( signatures.data(), signatures.size() ); -// fc::raw::unpack( s_sigs, u_sigs ); + fc::raw::unpack( s_sigs, u_sigs ); fc::crypto::blslib::bls_signature agg_sig = fc::crypto::blslib::aggregate(u_sigs); // TODO determine how we want to serialize signature -// auto packed = fc::raw::pack(agg_sig); -// -// auto copy_size = std::min(aggregate.size(), packed.size()); -// -// std::memcpy(aggregate.data(), packed.data(), copy_size); -// -// return packed.size(); - return 0; + auto packed = fc::raw::pack(agg_sig); + + auto copy_size = std::min(aggregate.size(), packed.size()); + + std::memcpy(aggregate.data(), packed.data(), copy_size); + + return packed.size(); } bool interface::bls_aggregate_verify( span signature, span digests, span pubs) const { @@ -489,9 +486,9 @@ namespace eosio { namespace chain { namespace webassembly { // TODO determine how we want to serialize signature // TODO determine how we want to serialize bls_public_key -// fc::raw::unpack( s_sig, u_sig ); -// fc::raw::unpack( s_pubs, u_pubs ); -// fc::raw::unpack( s_digests, u_digests ); + fc::raw::unpack( s_sig, u_sig ); + fc::raw::unpack( s_pubs, u_pubs ); + fc::raw::unpack( s_digests, u_digests ); bool result = fc::crypto::blslib::aggregate_verify(u_pubs, u_digests, u_sig); From e853e34ed50758de17154212e0150dfe5dacca9a Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 08:35:21 -0500 Subject: [PATCH 039/151] bls_private_key cleanup --- .../include/fc/crypto/bls_private_key.hpp | 46 +++----- .../libfc/src/crypto/bls_private_key.cpp | 105 ++---------------- libraries/libfc/test/test_bls.cpp | 3 +- 3 files changed, 23 insertions(+), 131 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 571d1b9d51..0738b248e6 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -1,16 +1,9 @@ #pragma once -#include -#include #include -#include #include #include -#include -#include -namespace fc { namespace crypto { namespace blslib { - - using namespace bls12_381; +namespace fc::crypto::blslib { namespace config { constexpr const char* bls_private_key_base_prefix = "PVT"; @@ -20,48 +13,35 @@ namespace fc { namespace crypto { namespace blslib { class bls_private_key { public: - bls_private_key() = default; bls_private_key( bls_private_key&& ) = default; bls_private_key( const bls_private_key& ) = default; - bls_private_key& operator= (const bls_private_key& ) = default; - - bls_private_key( vector seed ){ - _seed = seed; + bls_private_key& operator=( const bls_private_key& ) = default; + explicit bls_private_key( std::vector seed ) { + _seed = std::move(seed); } - bls_public_key get_public_key() const; - bls_signature sign( vector message ) const; - sha512 generate_shared_secret( const bls_public_key& pub ) const; - + // serialize to/from string + // TODO: determine format to use for string of private key + explicit bls_private_key(const string& base58str); std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; - static bls_private_key generate(); + bls_public_key get_public_key() const; + bls_signature sign( const vector& message ) const; -/* template< typename KeyType = r1::private_key_shim > - static bls_private_key generate_r1() { - return bls_private_key(storage_type(KeyType::generate())); - }*/ + static bls_private_key generate(); static bls_private_key regenerate( vector seed ) { - return bls_private_key(seed); + return bls_private_key(std::move(seed)); } - // serialize to/from string - explicit bls_private_key(const string& base58str); - - std::string serialize(); - private: - vector _seed; + std::vector _seed; - friend bool operator == ( const bls_private_key& p1, const bls_private_key& p2); - friend bool operator != ( const bls_private_key& p1, const bls_private_key& p2); - friend bool operator < ( const bls_private_key& p1, const bls_private_key& p2); friend struct reflector; }; // bls_private_key -} } } // fc::crypto::blslib +} // fc::crypto::blslib namespace fc { void to_variant(const crypto::blslib::bls_private_key& var, variant& vo, const fc::yield_function_t& yield = fc::yield_function_t()); diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index 3591a005f9..af5561485b 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -1,22 +1,21 @@ #include +#include #include #include -namespace fc { namespace crypto { namespace blslib { - - using namespace std; +namespace fc::crypto::blslib { bls_public_key bls_private_key::get_public_key() const { auto sk = bls12_381::secret_key(_seed); - g1 pk = bls12_381::public_key(sk); + bls12_381::g1 pk = bls12_381::public_key(sk); return bls_public_key(pk); } - bls_signature bls_private_key::sign( vector message ) const + bls_signature bls_private_key::sign( const vector& message ) const { - std::array sk = secret_key(_seed); - g2 sig = bls12_381::sign(sk, message); + std::array sk = bls12_381::secret_key(_seed); + bls12_381::g2 sig = bls12_381::sign(sk, message); return bls_signature(sig); } @@ -26,70 +25,6 @@ namespace fc { namespace crypto { namespace blslib { return bls_private_key(v); } - /*struct public_key_visitor : visitor { - template - bls_public_key::storage_type operator()(const KeyType& key) const - { - //return bls_public_key::storage_type(key.get_public_key()); - } - }; - - struct sign_visitor : visitor { - sign_visitor( const sha256& digest, bool require_canonical ) - :_digest(digest) - ,_require_canonical(require_canonical) - {} - - template - bls_signature::storage_type operator()(const KeyType& key) const - { - return bls_signature::storage_type(key.sign(_digest, _require_canonical)); - } - - const sha256& _digest; - bool _require_canonical; - }; - - bls_signature bls_private_key::sign( vector message ) const - { - //return bls_signature(std::visit(sign_visitor(digest, require_canonical), _seed)); - } - - struct generate_shared_secret_visitor : visitor { - generate_shared_secret_visitor( const bls_public_key::storage_type& pub_storage ) - :_pub_storage(pub_storage) - {} - - template - sha512 operator()(const KeyType& key) const - { - using PublicKeyType = typename KeyType::public_key_type; - return key.generate_shared_secret(std::template get(_pub_storage)); - } - - const bls_public_key::storage_type& _pub_storage; - }; - - sha512 bls_private_key::generate_shared_secret( const bls_public_key& pub ) const - - template - string to_wif( const Data& secret, const fc::yield_function_t& yield ) - { - { - return std::visit(generate_shared_secret_visitor(pub._storage), _seed); - }*/ - /* const size_t size_of_data_to_hash = sizeof(typename Data::data_type) + 1; - const size_t size_of_hash_bytes = 4; - char data[size_of_data_to_hash + size_of_hash_bytes]; - data[0] = (char)0x80; // this is the Bitcoin MainNet code - memcpy(&data[1], (const char*)&secret.serialize(), sizeof(typename Data::data_type)); - sha256 digest = sha256::hash(data, size_of_data_to_hash); - digest = sha256::hash(digest); - memcpy(data + size_of_data_to_hash, (char*)&digest, size_of_hash_bytes); - return to_base58(data, sizeof(data), yield); - } -*/ - template Data from_wif( const string& wif_key ) { @@ -107,8 +42,8 @@ namespace fc { namespace crypto { namespace blslib { static vector priv_parse_base58(const string& base58str) { - /* const auto pivot = base58str.find('_'); - + const auto pivot = base58str.find('_'); +/* if (pivot == std::string::npos) { // wif import using default_type = std::variant_alternative_t<0, bls_private_key::storage_type>; @@ -139,29 +74,7 @@ namespace fc { namespace crypto { namespace blslib { return std::string(config::private_key_base_prefix) + "_" + data_str;*/ } -/* std::string bls_private_key::serialize(){ - - PrivateKey sk = AugSchemeMPL().KeyGen(_seed); - - return Util::HexStr(sk.Serialize()); - }*/ - - std::ostream& operator<<(std::ostream& s, const bls_private_key& k) { - s << "bls_private_key(" << k.to_string() << ')'; - return s; - } -/* - bool operator == ( const bls_private_key& p1, const bls_private_key& p2) { - - return eq_comparator>::apply(p1._seed, p2._seed); - } - - bool operator < ( const bls_private_key& p1, const bls_private_key& p2){ - - - return less_comparator>::apply(p1._seed, p2._seed); - }*/ -} } } // fc::crypto::blslib +} // fc::crypto::blslib namespace fc { diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 6ba57e986e..2e2d5ca00b 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -38,8 +38,6 @@ std::vector message_2 = { 16, 38, 54, 125, 71, 214, 217, 78, fc::sha256 message_3 = fc::sha256("1097cf48a15ba1c618237d3d79f3c684c031a9844c27e6b95c6d27d8a5f401a1"); -std::vector message_4 = {143,10,193,195,104,126,124,222,124,64,177,164,240,234,110,18,142,236,191,66,223,47,235,248,75,9,172,99,178,26,239,78}; - //test a single key signature + verification BOOST_AUTO_TEST_CASE(bls_sig_verif) try { @@ -120,6 +118,7 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_hotstuff_types) try { BOOST_AUTO_TEST_CASE(bls_sig_verif_string_multi) try { bls_signature test_sig_single = bls_signature("SIG_BLS_23PuSu1B72cPe6wxGkKjAaaZqA1Ph79zSoW7omsKKUrnprbA3cJCJVhT48QKUG6ofjYTTg4BA4TrVENWyrxjTomwLX6TGdVg2RYhKH7Kk9X23K5ohuhKQcWQ6AwJJGVSbSp4"); + std::vector message_4 = {143,10,193,195,104,126,124,222,124,64,177,164,240,234,110,18,142,236,191,66,223,47,235,248,75,9,172,99,178,26,239,78}; bls_private_key sk = bls_private_key(seed_1); bls_public_key agg_key = sk.get_public_key(); From 064c5e5e154667abdf0a4680c56a925d379e565c Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 09:08:14 -0500 Subject: [PATCH 040/151] Fix warnings --- plugins/net_plugin/net_plugin.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 94860a39b1..91bd7450ab 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -2562,10 +2562,10 @@ namespace eosio { void dispatch_manager::bcast_hs_proposal_msg(const hs_proposal_message_ptr& msg) { if( my_impl->sync_master->syncing_from_peer() ) return; - hs_proposal_message & msg_val = *(msg.get()); - my_impl->connections.for_each_block_connection( [this, &msg_val]( auto& cp ) { + hs_proposal_message& msg_val = *(msg.get()); + my_impl->connections.for_each_block_connection( [&msg_val]( auto& cp ) { if( !cp->current() ) return true; - cp->strand.post( [this, cp, msg_val]() { + cp->strand.post( [cp, msg_val]() { if (cp->protocol_version >= proto_instant_finality) cp->enqueue( msg_val ); }); @@ -2575,10 +2575,10 @@ namespace eosio { void dispatch_manager::bcast_hs_vote_msg(const hs_vote_message_ptr& msg) { if( my_impl->sync_master->syncing_from_peer() ) return; - hs_vote_message & msg_val = *(msg.get()); - my_impl->connections.for_each_block_connection( [this, &msg_val]( auto& cp ) { + hs_vote_message& msg_val = *(msg.get()); + my_impl->connections.for_each_block_connection( [&msg_val]( auto& cp ) { if( !cp->current() ) return true; - cp->strand.post( [this, cp, msg_val]() { + cp->strand.post( [cp, msg_val]() { if (cp->protocol_version >= proto_instant_finality) cp->enqueue( msg_val ); }); @@ -2588,10 +2588,10 @@ namespace eosio { void dispatch_manager::bcast_hs_new_block_msg(const hs_new_block_message_ptr& msg) { if( my_impl->sync_master->syncing_from_peer() ) return; - hs_new_block_message & msg_val = *(msg.get()); - my_impl->connections.for_each_block_connection( [this, &msg_val]( auto& cp ) { + hs_new_block_message& msg_val = *(msg.get()); + my_impl->connections.for_each_block_connection( [&msg_val]( auto& cp ) { if( !cp->current() ) return true; - cp->strand.post( [this, cp, msg_val]() { + cp->strand.post( [cp, msg_val]() { if (cp->protocol_version >= proto_instant_finality) cp->enqueue( msg_val ); }); @@ -2601,10 +2601,10 @@ namespace eosio { void dispatch_manager::bcast_hs_new_view_msg(const hs_new_view_message_ptr& msg) { if( my_impl->sync_master->syncing_from_peer() ) return; - hs_new_view_message & msg_val = *(msg.get()); - my_impl->connections.for_each_block_connection( [this, &msg_val]( auto& cp ) { + hs_new_view_message& msg_val = *(msg.get()); + my_impl->connections.for_each_block_connection( [&msg_val]( auto& cp ) { if( !cp->current() ) return true; - cp->strand.post( [this, cp, msg_val]() { + cp->strand.post( [cp, msg_val]() { if (cp->protocol_version >= proto_instant_finality) cp->enqueue( msg_val ); }); From 829f956e1816c1538692f5299d90039ea756cd2d Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 09:08:37 -0500 Subject: [PATCH 041/151] Attempt to fix libtester --- libraries/chain/controller.cpp | 1 + libraries/chain/include/eosio/chain/controller.hpp | 10 +++++++++- .../include/eosio/chain_plugin/chain_plugin.hpp | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index cda3c89293..04515b4c74 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index eb29f0690b..934ed25dac 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include @@ -22,6 +21,15 @@ namespace eosio { namespace vm { class wasm_allocator; }} namespace eosio { namespace chain { + struct hs_proposal_message; + struct hs_vote_message; + struct hs_new_view_message; + struct hs_new_block_message; + using hs_proposal_message_ptr = std::shared_ptr; + using hs_vote_message_ptr = std::shared_ptr; + using hs_new_view_message_ptr = std::shared_ptr; + using hs_new_block_message_ptr = std::shared_ptr; + class authorization_manager; namespace resource_limits { diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 094bf056b1..b7da786831 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include From 5df30b62544eb63c08ee0881a927ed6026e4a038 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 13:16:57 -0500 Subject: [PATCH 042/151] Add virtual destructor to remove warning --- libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index 3caf0c7709..0f293efaf5 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -20,6 +20,8 @@ namespace eosio { namespace hotstuff { class base_pacemaker { public: + virtual ~base_pacemaker() = default; + //TODO: discuss virtual uint32_t get_quorum_threshold() = 0; From 48ec519a5e7a9b573481aa2139244a9b52a9af08 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 13:17:51 -0500 Subject: [PATCH 043/151] Remove aggregate_signatures protocol feature and host functions. Replace by bls_* primitive host functions. --- libraries/chain/controller.cpp | 11 --- .../eosio/chain/protocol_feature_manager.hpp | 3 +- .../eos-vm-oc/intrinsic_mapping.hpp | 6 +- .../eosio/chain/webassembly/interface.hpp | 12 --- libraries/chain/protocol_feature_manager.cpp | 9 -- libraries/chain/webassembly/crypto.cpp | 84 ------------------- .../chain/webassembly/runtimes/eos-vm.cpp | 6 -- 7 files changed, 2 insertions(+), 129 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 04515b4c74..8a5a6e9622 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -341,7 +341,6 @@ struct controller_impl { set_activation_handler(); set_activation_handler(); set_activation_handler(); - set_activation_handler(); set_activation_handler(); self.irreversible_block.connect([this](const block_state_ptr& bsp) { @@ -3877,16 +3876,6 @@ void controller_impl::on_activation( } ); } -template<> -void controller_impl::on_activation() { - db.modify( db.get(), [&]( auto& ps ) { - add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "bls_verify" ); - add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "bls_aggregate_pubkeys" ); - add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "bls_aggregate_sigs" ); - add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "bls_aggregate_verify" ); - } ); -} - template<> void controller_impl::on_activation() { db.modify( db.get(), [&]( auto& ps ) { diff --git a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp index 31b400cb5b..a998cf43ac 100644 --- a/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp +++ b/libraries/chain/include/eosio/chain/protocol_feature_manager.hpp @@ -36,8 +36,7 @@ enum class builtin_protocol_feature_t : uint32_t { crypto_primitives = 19, get_block_num = 20, bls_primitives = 21, - aggregate_signatures = 22, - instant_finality = 23, + instant_finality = 22, reserved_private_fork_protocol_features = 500000, }; diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp index 6d498de175..ea92a9cf86 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp @@ -277,11 +277,7 @@ inline constexpr auto get_intrinsic_table() { "env.bls_pairing", "env.bls_g1_map", "env.bls_g2_map", - "env.bls_fp_mod", - "env.bls_verify", - "env.bls_aggregate_pubkeys", - "env.bls_aggregate_sigs", - "env.bls_aggregate_verify" + "env.bls_fp_mod" ); } inline constexpr std::size_t find_intrinsic_index(std::string_view hf) { diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index 5bba936a86..59fac5078a 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -1896,18 +1896,6 @@ namespace webassembly { */ int32_t bls_fp_mod(span s, span result) const; - // TODO add comment - bool bls_verify( span signature, span digest, span pub) const; - - // TODO add comment - int32_t bls_aggregate_pubkeys( span pubkeys, span aggregate) const; - - // TODO add comment - int32_t bls_aggregate_sigs( span signatures, span aggregate) const; - - // TODO add comment - bool bls_aggregate_verify( span signature, span digests, span pubs) const; - // compiler builtins api void __ashlti3(legacy_ptr, uint64_t, uint64_t, uint32_t) const; void __ashrti3(legacy_ptr, uint64_t, uint64_t, uint32_t) const; diff --git a/libraries/chain/protocol_feature_manager.cpp b/libraries/chain/protocol_feature_manager.cpp index 7d04ca6a3c..5146f736b4 100644 --- a/libraries/chain/protocol_feature_manager.cpp +++ b/libraries/chain/protocol_feature_manager.cpp @@ -269,15 +269,6 @@ Enables new `get_block_num` intrinsic which returns the current block number. Builtin protocol feature: BLS_PRIMITIVES Adds new cryptographic host functions - Add, multiply, multi-exponentiation and pairing functions for the bls12-381 elliptic curve. -*/ - {} - } ) - ( builtin_protocol_feature_t::aggregate_signatures, builtin_protocol_feature_spec{ - "AGGREGATE_SIGNATURES", - fc::variant("997de2624c039e38993953ff1091aeb1ecff723d06fe78a5ade08931b0b22896").as(), - // SHA256 hash of the raw message below within the comment delimiters (do not modify message below). -/* -Builtin protocol feature: AGGREGATE_SIGNATURES */ {} } ) diff --git a/libraries/chain/webassembly/crypto.cpp b/libraries/chain/webassembly/crypto.cpp index 78107a6564..9fa4d0bf63 100644 --- a/libraries/chain/webassembly/crypto.cpp +++ b/libraries/chain/webassembly/crypto.cpp @@ -411,88 +411,4 @@ namespace eosio { namespace chain { namespace webassembly { return return_code::success; } - bool interface::bls_verify( span signature, span digest, span pub) const { - - fc::crypto::blslib::bls_signature u_sig; - fc::crypto::blslib::bls_public_key u_pub; - vector u_digest; - - fc::datastream s_sig( signature.data(), signature.size() ); - fc::datastream s_pub( pub.data(), pub.size() ); - fc::datastream s_digest( digest.data(), digest.size() ); - - // TODO determine how we want to serialize signature - fc::raw::unpack( s_sig, u_sig ); - fc::raw::unpack( s_pub, u_pub ); - fc::raw::unpack( s_digest, u_digest ); - - std::cerr << u_pub.to_string() << "\n"; - std::cerr << u_sig.to_string() << "\n"; - - bool result = fc::crypto::blslib::verify(u_pub, u_digest, u_sig); - - return result; - } - - int32_t interface::bls_aggregate_pubkeys( span pubkeys, span aggregate) const { - - vector u_pubkeys; - - fc::datastream s_pubkeys( pubkeys.data(), pubkeys.size() ); - - // TODO determine how we want to serialize bls_public_key - fc::raw::unpack( s_pubkeys, u_pubkeys ); - - fc::crypto::blslib::bls_public_key agg_pubkey = fc::crypto::blslib::aggregate(u_pubkeys); - - auto packed = fc::raw::pack(agg_pubkey); - - auto copy_size = std::min(aggregate.size(), packed.size()); - - std::memcpy(aggregate.data(), packed.data(), copy_size); - - return packed.size(); - } - - int32_t interface::bls_aggregate_sigs( span signatures, span aggregate) const { - - vector u_sigs; - - fc::datastream s_sigs( signatures.data(), signatures.size() ); - - fc::raw::unpack( s_sigs, u_sigs ); - - fc::crypto::blslib::bls_signature agg_sig = fc::crypto::blslib::aggregate(u_sigs); - - // TODO determine how we want to serialize signature - auto packed = fc::raw::pack(agg_sig); - - auto copy_size = std::min(aggregate.size(), packed.size()); - - std::memcpy(aggregate.data(), packed.data(), copy_size); - - return packed.size(); - } - - bool interface::bls_aggregate_verify( span signature, span digests, span pubs) const { - - fc::crypto::blslib::bls_signature u_sig; - vector u_pubs; - vector> u_digests; - - fc::datastream s_sig( signature.data(), signature.size() ); - fc::datastream s_pubs( pubs.data(), pubs.size() ); - fc::datastream s_digests( digests.data(), digests.size() ); - - // TODO determine how we want to serialize signature - // TODO determine how we want to serialize bls_public_key - fc::raw::unpack( s_sig, u_sig ); - fc::raw::unpack( s_pubs, u_pubs ); - fc::raw::unpack( s_digests, u_digests ); - - bool result = fc::crypto::blslib::aggregate_verify(u_pubs, u_digests, u_sig); - - return result; - } - }}} // ns eosio::chain::webassembly diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index 0680c5c940..e23f91b90e 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -641,12 +641,6 @@ REGISTER_CF_HOST_FUNCTION( bls_g1_map ); REGISTER_CF_HOST_FUNCTION( bls_g2_map ); REGISTER_CF_HOST_FUNCTION( bls_fp_mod ); -// aggregate_signatures protocol feature -REGISTER_CF_HOST_FUNCTION( bls_verify ); -REGISTER_CF_HOST_FUNCTION( bls_aggregate_pubkeys ); -REGISTER_CF_HOST_FUNCTION( bls_aggregate_sigs ); -REGISTER_CF_HOST_FUNCTION( bls_aggregate_verify ); - } // namespace webassembly } // namespace chain } // namespace eosio From 9873720c97894582d6389453cb25269c89ca50a1 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 14:36:03 -0500 Subject: [PATCH 044/151] Move chain_pacemaker from producer_plugin to chain_plugin. --- libraries/chain/controller.cpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 8 +- .../include/eosio/hotstuff/base_pacemaker.hpp | 8 +- .../eosio/hotstuff/chain_pacemaker.hpp | 22 +++--- .../include/eosio/hotstuff/qc_chain.hpp | 4 +- libraries/hotstuff/qc_chain.cpp | 4 +- plugins/chain_plugin/CMakeLists.txt | 2 +- plugins/chain_plugin/chain_plugin.cpp | 72 +++++++++++------ .../eosio/chain_plugin/chain_plugin.hpp | 11 +++ plugins/net_plugin/net_plugin.cpp | 37 ++------- plugins/producer_plugin/CMakeLists.txt | 2 +- .../eosio/producer_plugin/producer_plugin.hpp | 8 -- plugins/producer_plugin/producer_plugin.cpp | 78 +------------------ tests/chain_plugin_tests.cpp | 7 +- tests/get_producers_tests.cpp | 5 +- tests/get_table_seckey_tests.cpp | 3 +- tests/get_table_tests.cpp | 9 ++- tests/test_chain_plugin.cpp | 7 +- 18 files changed, 112 insertions(+), 177 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 8a5a6e9622..d6cfd302ec 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +//#include #include #include diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index f8b23498ec..92b04e7693 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -100,19 +100,19 @@ namespace eosio { namespace hotstuff { #endif //=============================================================================================== - chain_pacemaker::chain_pacemaker(controller* chain, std::set my_producers, bool info_logging, bool error_logging) + chain_pacemaker::chain_pacemaker(controller* chain, std::set my_producers, bool info_logging, bool error_logging) : _chain(chain), - _qc_chain("default"_n, this, my_producers, info_logging, error_logging) + _qc_chain("default"_n, this, std::move(my_producers), info_logging, error_logging) { } // Called internally by the chain_pacemaker to decide whether it should do something or not, based on feature activation. // Only methods called by the outside need to call this; methods called by qc_chain only don't need to check for enable(). - bool chain_pacemaker::enabled() { + bool chain_pacemaker::enabled() const { return _chain->is_builtin_activated( builtin_protocol_feature_t::instant_finality ); } - void chain_pacemaker::get_state( finalizer_state & fs ) { + void chain_pacemaker::get_state( finalizer_state& fs ) const { if (enabled()) _qc_chain.get_state( fs ); // get_state() takes scare of finer-grained synchronization internally } diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index 0f293efaf5..9d172360d5 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -34,10 +34,10 @@ namespace eosio { namespace hotstuff { virtual std::vector get_finalizers() = 0; //outbound communications; 'id' is the producer name (can be ignored if/when irrelevant to the implementer) - virtual void send_hs_proposal_msg(const hs_proposal_message & msg, name id) = 0; - virtual void send_hs_vote_msg(const hs_vote_message & msg, name id) = 0; - virtual void send_hs_new_view_msg(const hs_new_view_message & msg, name id) = 0; - virtual void send_hs_new_block_msg(const hs_new_block_message & msg, name id) = 0; + virtual void send_hs_proposal_msg(const hs_proposal_message& msg, name id) = 0; + virtual void send_hs_vote_msg(const hs_vote_message& msg, name id) = 0; + virtual void send_hs_new_view_msg(const hs_new_view_message& msg, name id) = 0; + virtual void send_hs_new_block_msg(const hs_new_block_message& msg, name id) = 0; }; }} diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index 50471c59cd..be53d83fcf 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -13,16 +13,16 @@ namespace eosio { namespace hotstuff { //class-specific functions - chain_pacemaker(controller* chain, std::set my_producers, bool info_logging, bool error_logging); + chain_pacemaker(controller* chain, std::set my_producers, bool info_logging, bool error_logging); void beat(); - 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 - void on_hs_new_view_msg(const hs_new_view_message & msg); //new view msg event handler - void on_hs_new_block_msg(const hs_new_block_message & msg); //new block msg event handler + 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 + void on_hs_new_view_msg(const hs_new_view_message& msg); //new view msg event handler + void on_hs_new_block_msg(const hs_new_block_message& msg); //new block msg event handler - void get_state( finalizer_state & fs ); + void get_state( finalizer_state& fs ) const; //base_pacemaker interface functions @@ -35,10 +35,10 @@ namespace eosio { namespace hotstuff { uint32_t get_quorum_threshold(); - void send_hs_proposal_msg(const hs_proposal_message & msg, name id); - void send_hs_vote_msg(const hs_vote_message & msg, name id); - void send_hs_new_view_msg(const hs_new_view_message & msg, name id); - void send_hs_new_block_msg(const hs_new_block_message & msg, name id); + void send_hs_proposal_msg(const hs_proposal_message& msg, name id); + void send_hs_vote_msg(const hs_vote_message& msg, name id); + void send_hs_new_view_msg(const hs_new_view_message& msg, name id); + void send_hs_new_block_msg(const hs_new_block_message& msg, name id); private: @@ -46,7 +46,7 @@ namespace eosio { namespace hotstuff { name debug_leader_remap(name n); // Check if consensus upgrade feature is activated - bool enabled(); + bool enabled() const; // This serializes all messages (high-level requests) to the qc_chain core. // For maximum safety, the qc_chain core will only process one request at a time. diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 54126e8a28..336ad61bb7 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -87,7 +87,7 @@ namespace eosio { namespace hotstuff { // returns false if proposal with that same ID already exists at the store of its height bool insert_proposal(const hs_proposal_message & proposal); - void get_state( finalizer_state & fs ); + void get_state( finalizer_state& fs ) const; uint32_t positive_bits_count(fc::unsigned_int value); @@ -159,7 +159,7 @@ namespace eosio { namespace hotstuff { // And if the chain_pacemaker::_hotstuff_global_mutex locking strategy is ever // changed, then this probably needs to be reviewed as well. // - std::mutex _state_mutex; + mutable std::mutex _state_mutex; #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE // keep one proposal store (id -> proposal) by each height (height -> proposal store) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 5e278a8045..3bab42d27d 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -99,7 +99,7 @@ namespace eosio { namespace hotstuff { #endif } - void qc_chain::get_state( finalizer_state & fs ) { + void qc_chain::get_state( finalizer_state& fs ) const { std::lock_guard g( _state_mutex ); fs.chained_mode = _chained_mode; fs.b_leaf = _b_leaf; @@ -313,7 +313,7 @@ namespace eosio { namespace hotstuff { qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, bool info_logging, bool error_logging) : _id(id), _pacemaker(pacemaker), - _my_producers(my_producers), + _my_producers(std::move(my_producers)), _log(info_logging), _errors(error_logging) { diff --git a/plugins/chain_plugin/CMakeLists.txt b/plugins/chain_plugin/CMakeLists.txt index ae21541990..71a85e4f67 100644 --- a/plugins/chain_plugin/CMakeLists.txt +++ b/plugins/chain_plugin/CMakeLists.txt @@ -11,7 +11,7 @@ if(EOSIO_ENABLE_DEVELOPER_OPTIONS) target_compile_definitions(chain_plugin PUBLIC EOSIO_DEVELOPER) endif() -target_link_libraries( chain_plugin eosio_chain custom_appbase appbase resource_monitor_plugin Boost::bimap ) +target_link_libraries( chain_plugin eosio_chain custom_appbase appbase resource_monitor_plugin hotstuff Boost::bimap ) target_include_directories( chain_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../chain_interface/include" "${CMAKE_CURRENT_SOURCE_DIR}/../../libraries/appbase/include" "${CMAKE_CURRENT_SOURCE_DIR}/../resource_monitor_plugin/include") add_subdirectory( test ) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 5795c22cfd..3381c48b11 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -207,7 +208,7 @@ class chain_plugin_impl { std::optional applied_transaction_connection; std::optional block_start_connection; - + std::optional _chain_pacemaker; std::optional _account_query_db; std::optional _trx_retry_db; chain_apis::trx_finality_status_processing_ptr _trx_finality_status_processing; @@ -1108,7 +1109,13 @@ void chain_plugin_impl::plugin_initialize(const variables_map& options) { } chain->add_indices(); } FC_LOG_AND_RETHROW() +} +void chain_plugin::create_pacemaker(std::set my_producers) { + EOS_ASSERT( !my->_chain_pacemaker, plugin_config_exception, "duplicate chain_pacemaker initialization" ); + const bool info_logging = true; + const bool error_logging = true; + my->_chain_pacemaker.emplace(&chain(), std::move(my_producers), info_logging, error_logging); } void chain_plugin::plugin_initialize(const variables_map& options) { @@ -1120,6 +1127,7 @@ void chain_plugin_impl::plugin_startup() { try { EOS_ASSERT( chain_config->read_mode != db_read_mode::IRREVERSIBLE || !accept_transactions, plugin_config_exception, "read-mode = irreversible. transactions should not be enabled by enable_accept_transactions" ); + EOS_ASSERT( _chain_pacemaker, plugin_config_exception, "chain_pacemaker not initialization" ); try { auto shutdown = [](){ return app().quit(); }; auto check_shutdown = [](){ return app().is_quiting(); }; @@ -1211,7 +1219,7 @@ chain_apis::read_write chain_plugin::get_read_write_api(const fc::microseconds& } chain_apis::read_only chain_plugin::get_read_only_api(const fc::microseconds& http_max_response_time) const { - return chain_apis::read_only(chain(), my->_account_query_db, get_abi_serializer_max_time(), http_max_response_time, my->_trx_finality_status_processing.get()); + return chain_apis::read_only(chain(), my->_account_query_db, my->_chain_pacemaker, get_abi_serializer_max_time(), http_max_response_time, my->_trx_finality_status_processing.get()); } @@ -2640,31 +2648,51 @@ read_only::get_consensus_parameters(const get_consensus_parameters_params&, cons read_only::get_finalizer_state_results read_only::get_finalizer_state(const get_finalizer_state_params&, const fc::time_point& deadline ) const { get_finalizer_state_results results; - // TODO: move to producer_plugin -// if ( producer_plug ) { // producer_plug is null when called from chain_plugin_tests.cpp and get_table_tests.cpp -// finalizer_state fs; -// producer_plug->get_finalizer_state( fs ); -// results.chained_mode = fs.chained_mode; -// results.b_leaf = fs.b_leaf; -// results.b_lock = fs.b_lock; -// results.b_exec = fs.b_exec; -// results.b_finality_violation = fs.b_finality_violation; -// results.block_exec = fs.block_exec; -// results.pending_proposal_block = fs.pending_proposal_block; -// results.v_height = fs.v_height; -// results.high_qc = fs.high_qc; -// results.current_qc = fs.current_qc; -// results.schedule = fs.schedule; -// for (auto proposal: fs.proposals) { -// chain::hs_proposal_message & p = proposal.second; -// results.proposals.push_back( hs_complete_proposal_message( p ) ); -// } -// } + + if ( chain_pacemaker ) { // producer_plug is null when called from chain_plugin_tests.cpp and get_table_tests.cpp + finalizer_state fs; + chain_pacemaker->get_state( fs ); + results.chained_mode = fs.chained_mode; + results.b_leaf = fs.b_leaf; + results.b_lock = fs.b_lock; + results.b_exec = fs.b_exec; + results.b_finality_violation = fs.b_finality_violation; + results.block_exec = fs.block_exec; + results.pending_proposal_block = fs.pending_proposal_block; + results.v_height = fs.v_height; + results.high_qc = fs.high_qc; + results.current_qc = fs.current_qc; + results.schedule = fs.schedule; + for (auto proposal: fs.proposals) { + chain::hs_proposal_message & p = proposal.second; + results.proposals.push_back( hs_complete_proposal_message( p ) ); + } + } return results; } } // namespace chain_apis +void chain_plugin::notify_hs_vote_message( const hs_vote_message& msg ) { + my->_chain_pacemaker->on_hs_vote_msg(msg); +}; + +void chain_plugin::notify_hs_proposal_message( const hs_proposal_message& msg ) { + my->_chain_pacemaker->on_hs_proposal_msg(msg); +}; + +void chain_plugin::notify_hs_new_view_message( const hs_new_view_message& msg ) { + my->_chain_pacemaker->on_hs_new_view_msg(msg); +}; + +void chain_plugin::notify_hs_new_block_message( const hs_new_block_message& msg ) { + my->_chain_pacemaker->on_hs_new_block_msg(msg); +}; + +void chain_plugin::notify_hs_block_produced() { + my->_chain_pacemaker->beat(); +} + fc::variant chain_plugin::get_log_trx_trace(const transaction_trace_ptr& trx_trace ) const { fc::variant pretty_output; try { diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index b7da786831..a5894951ab 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -28,6 +28,7 @@ namespace fc { class variant; } namespace eosio { namespace chain { class abi_resolver; } + namespace hotstuff { class chain_pacemaker; } using chain::controller; using std::unique_ptr; @@ -140,6 +141,7 @@ class api_base { class read_only : public api_base { const controller& db; const std::optional& aqdb; + const std::optional& chain_pacemaker; const fc::microseconds abi_serializer_max_time; const fc::microseconds http_max_response_time; bool shorten_abi_errors = true; @@ -150,10 +152,12 @@ class read_only : public api_base { static const string KEYi64; read_only(const controller& db, const std::optional& aqdb, + const std::optional& chain_pacemaker, const fc::microseconds& abi_serializer_max_time, const fc::microseconds& http_max_response_time, const trx_finality_status_processing* trx_finality_status_proc) : db(db) , aqdb(aqdb) + , chain_pacemaker(chain_pacemaker) , abi_serializer_max_time(abi_serializer_max_time) , http_max_response_time(http_max_response_time) , trx_finality_status_proc(trx_finality_status_proc) { @@ -1027,6 +1031,13 @@ class chain_plugin : public plugin { // Only call this after plugin_initialize()! const controller& chain() const; + void create_pacemaker(std::set my_producers); + void notify_hs_vote_message( const chain::hs_vote_message& msg ); + void notify_hs_proposal_message( const chain::hs_proposal_message& msg ); + void notify_hs_new_view_message( const chain::hs_new_view_message& msg ); + void notify_hs_new_block_message( const chain::hs_new_block_message& msg ); + void notify_hs_block_produced(); + chain::chain_id_type get_chain_id() const; fc::microseconds get_abi_serializer_max_time() const; bool api_accept_transactions() const; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 91bd7450ab..42167d89a9 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -3632,48 +3632,21 @@ namespace eosio { } void connection::handle_message( const hs_vote_message& msg ) { - //peer_ilog( this, "received confirmation message" ); - //ilog("received confirmation message"); - - if (my_impl->producer_plug != nullptr){ - hs_vote_message_ptr msg_ptr = std::make_shared(msg); - my_impl->producer_plug->notify_hs_vote_message(msg_ptr); - } - + my_impl->chain_plug->notify_hs_vote_message(msg); } void connection::handle_message( const hs_proposal_message& msg ) { - //peer_ilog( this, "received consensus message" ); - //ilog("received consensus message"); - - if (my_impl->producer_plug != nullptr){ - hs_proposal_message_ptr msg_ptr = std::make_shared(msg); - my_impl->producer_plug->notify_hs_proposal_message(msg_ptr); - } - + my_impl->chain_plug->notify_hs_proposal_message(msg); } void connection::handle_message( const hs_new_view_message& msg ) { - //peer_ilog( this, "received new view message" ); - //ilog("received new view message"); - - if (my_impl->producer_plug != nullptr){ - hs_new_view_message_ptr msg_ptr = std::make_shared(msg); - my_impl->producer_plug->notify_hs_new_view_message(msg_ptr); - } - + my_impl->chain_plug->notify_hs_new_view_message(msg); } void connection::handle_message( const hs_new_block_message& msg ) { - //peer_ilog( this, "received new block message" ); - //ilog("received new block message"); - - if (my_impl->producer_plug != nullptr){ - hs_new_block_message_ptr msg_ptr = std::make_shared(msg); - my_impl->producer_plug->notify_hs_new_block_message(msg_ptr); - } - + my_impl->chain_plug->notify_hs_new_block_message(msg); } + size_t calc_trx_size( const packed_transaction_ptr& trx ) { return trx->get_estimated_size(); } diff --git a/plugins/producer_plugin/CMakeLists.txt b/plugins/producer_plugin/CMakeLists.txt index 3fd6eaef1d..454652e323 100644 --- a/plugins/producer_plugin/CMakeLists.txt +++ b/plugins/producer_plugin/CMakeLists.txt @@ -5,7 +5,7 @@ add_library( producer_plugin ${HEADERS} ) -target_link_libraries( producer_plugin chain_plugin http_client_plugin signature_provider_plugin appbase eosio_chain hotstuff) +target_link_libraries( producer_plugin chain_plugin http_client_plugin signature_provider_plugin appbase eosio_chain) target_include_directories( producer_plugin PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../chain_interface/include" ) diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index ad1bb8ebfb..6e4e687087 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -3,7 +3,6 @@ #include #include #include -#include #include #include @@ -107,13 +106,6 @@ class producer_plugin : public appbase::plugin { scheduled_protocol_feature_activations get_scheduled_protocol_feature_activations() const; void schedule_protocol_feature_activations(const scheduled_protocol_feature_activations& schedule); - void notify_hs_vote_message( const chain::hs_vote_message_ptr& msg); - void notify_hs_proposal_message( const chain::hs_proposal_message_ptr& msg ); - void notify_hs_new_view_message( const chain::hs_new_view_message_ptr& msg); - void notify_hs_new_block_message( const chain::hs_new_block_message_ptr& msg ); - - bool get_finalizer_state(finalizer_state & fs) const; - fc::variants get_supported_protocol_features( const get_supported_protocol_features_params& params ) const; get_account_ram_corrections_result get_account_ram_corrections( const get_account_ram_corrections_params& params ) const; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index ca208321f7..db1a0da794 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -383,11 +383,6 @@ class producer_plugin_impl : public std::enable_shared_from_this()) , _ro_timer(io) {} - void notify_hs_vote_message( const hs_vote_message_ptr& msg); - void notify_hs_proposal_message( const hs_proposal_message_ptr& msg ); - void notify_hs_new_view_message( const hs_new_view_message_ptr& msg); - void notify_hs_new_block_message( const hs_new_block_message_ptr& msg ); - void schedule_production_loop(); void schedule_maybe_produce_block(bool exhausted); void produce_block(); @@ -556,8 +551,6 @@ class producer_plugin_impl : public std::enable_shared_from_this _irreversible_block_connection; std::optional _block_start_connection; - std::optional _chain_pacemaker; - /* * HACK ALERT * Boost timers can be in a state where a handler has not yet executed but is not abortable. @@ -1320,8 +1313,7 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia _snapshot_scheduler.set_db_path(_snapshots_dir); _snapshot_scheduler.set_snapshots_path(_snapshots_dir); - EOS_ASSERT( !_chain_pacemaker, plugin_config_exception, "duplicate chain_pacemaker initialization" ); - _chain_pacemaker.emplace(&chain, _producers, true, true); + chain_plug->create_pacemaker(_producers); } void producer_plugin::plugin_initialize(const boost::program_options::variables_map& options) { @@ -1601,30 +1593,6 @@ void producer_plugin_impl::schedule_protocol_feature_activations(const producer_ _protocol_features_signaled = false; } -void producer_plugin::notify_hs_vote_message( const hs_vote_message_ptr& msg){ - my->notify_hs_vote_message(msg); -}; - -void producer_plugin::notify_hs_proposal_message( const hs_proposal_message_ptr& msg ){ - my->notify_hs_proposal_message(msg); -}; - -void producer_plugin::notify_hs_new_view_message( const hs_new_view_message_ptr& msg){ - my->notify_hs_new_view_message(msg); -}; - -void producer_plugin::notify_hs_new_block_message( const hs_new_block_message_ptr& msg ){ - my->notify_hs_new_block_message(msg); -}; - -bool producer_plugin::get_finalizer_state( finalizer_state & fs ) const { - if (my->_chain_pacemaker) { - my->_chain_pacemaker->get_state( fs ); - return true; - } - return false; -} - void producer_plugin::schedule_protocol_feature_activations(const scheduled_protocol_feature_activations& schedule) { my->schedule_protocol_feature_activations(schedule); } @@ -2714,27 +2682,6 @@ static auto maybe_make_debug_time_logger() -> std::optionalon_hs_vote_msg(*msg); -}; - -void producer_plugin_impl::notify_hs_proposal_message( const hs_proposal_message_ptr& msg ){ - if (_chain_pacemaker) - _chain_pacemaker->on_hs_proposal_msg(*msg); -}; - -void producer_plugin_impl::notify_hs_new_view_message( const hs_new_view_message_ptr& msg ){ - if (_chain_pacemaker) - _chain_pacemaker->on_hs_new_view_msg(*msg); -}; - -void producer_plugin_impl::notify_hs_new_block_message( const hs_new_block_message_ptr& msg ){ - if (_chain_pacemaker) - _chain_pacemaker->on_hs_new_block_msg(*msg); -}; - - void producer_plugin_impl::produce_block() { auto start = fc::time_point::now(); _time_tracker.add_idle_time(start); @@ -2782,28 +2729,7 @@ void producer_plugin_impl::produce_block() { block_state_ptr new_bs = chain.head_block_state(); -/* const auto& hbs = chain.head_block_state(); - const auto& active_schedule = hbs->active_schedule.producers; -*/ - //if we're producing after chain has activated, and we're not currently in the middle of a view - //if (hbs->header.producer != name("eosio") && - // (_qc_chain._qc_chain_state == qc_chain::qc_chain_state::initializing || _qc_chain._qc_chain_state == qc_chain::qc_chain_state::finished_view)){ - // _qc_chain.create_new_view(*hbs); //we create a new view - //} - - if (_chain_pacemaker) { - - // FIXME/REVIEW: For now, we are not participating in the IF protocol as proposers - // when we have the enable-stale-production plugin configuration option set. - // NOTE: This entire feature will likely disappear (deleted) before delivery, as - // hotstuff activation only takes place, realistically, after the - // stale-block-production producing/proposing boot node has been gone. - // Stale producing nodes being hotstuff leaders is probably fine. - if (!_enable_stale_production_config) - _chain_pacemaker->beat(); - else - ilog("producer plugin will not check for Instant Finality proposer (and maybe also leader) role due to enable-stale-production option set."); - } + chain_plug->notify_hs_block_produced(); br.total_time += fc::time_point::now() - start; diff --git a/tests/chain_plugin_tests.cpp b/tests/chain_plugin_tests.cpp index cc6d329c05..b73d4942c2 100644 --- a/tests/chain_plugin_tests.cpp +++ b/tests/chain_plugin_tests.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -89,7 +90,7 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, validating_tester ) try { char headnumstr[20]; sprintf(headnumstr, "%d", headnum); chain_apis::read_only::get_raw_block_params param{headnumstr}; - chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); + chain_apis::read_only plugin(*(this->control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); // block should be decoded successfully auto block = plugin.get_raw_block(param, fc::time_point::maximum()); @@ -133,7 +134,7 @@ BOOST_FIXTURE_TEST_CASE( get_block_with_invalid_abi, validating_tester ) try { BOOST_FIXTURE_TEST_CASE( get_consensus_parameters, validating_tester ) try { produce_blocks(1); - chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), nullptr); + chain_apis::read_only plugin(*(this->control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), nullptr); auto parms = plugin.get_consensus_parameters({}, fc::time_point::maximum()); @@ -180,7 +181,7 @@ BOOST_FIXTURE_TEST_CASE( get_account, validating_tester ) try { produce_block(); - chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), nullptr); + chain_apis::read_only plugin(*(this->control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), nullptr); chain_apis::read_only::get_account_params p{"alice"_n}; diff --git a/tests/get_producers_tests.cpp b/tests/get_producers_tests.cpp index e22620f887..1fd574a2ee 100644 --- a/tests/get_producers_tests.cpp +++ b/tests/get_producers_tests.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -16,7 +17,7 @@ using namespace eosio::testing; BOOST_AUTO_TEST_CASE( get_producers) { try { tester chain; - eosio::chain_apis::read_only plugin(*(chain.control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); + eosio::chain_apis::read_only plugin(*(chain.control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); eosio::chain_apis::read_only::get_producers_params params = { .json = true, .lower_bound = "", .limit = 21 }; auto results = plugin.get_producers(params, fc::time_point::maximum()); @@ -52,7 +53,7 @@ BOOST_AUTO_TEST_CASE( get_producers_from_table) { try { // ensure that enough voting is occurring so that producer1111 is elected as the producer chain.cross_15_percent_threshold(); - eosio::chain_apis::read_only plugin(*(chain.control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); + eosio::chain_apis::read_only plugin(*(chain.control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); eosio::chain_apis::read_only::get_producers_params params = { .json = true, .lower_bound = "", .limit = 21 }; auto results = plugin.get_producers(params, fc::time_point::maximum()); diff --git a/tests/get_table_seckey_tests.cpp b/tests/get_table_seckey_tests.cpp index 2693390b64..b3ad3b06a5 100644 --- a/tests/get_table_seckey_tests.cpp +++ b/tests/get_table_seckey_tests.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -43,7 +44,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_next_key_test, validating_tester ) try { set_abi( "test"_n, test_contracts::get_table_seckey_test_abi() ); produce_block(); - chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); + chain_apis::read_only plugin(*(this->control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); chain_apis::read_only::get_table_rows_params params = []{ chain_apis::read_only::get_table_rows_params params{}; params.json=true; diff --git a/tests/get_table_tests.cpp b/tests/get_table_tests.cpp index 156a4d0579..b4b68bd7fc 100644 --- a/tests/get_table_tests.cpp +++ b/tests/get_table_tests.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -90,7 +91,7 @@ BOOST_FIXTURE_TEST_CASE( get_scope_test, validating_tester ) try { produce_blocks(1); // iterate over scope - eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); + eosio::chain_apis::read_only plugin(*(this->control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); eosio::chain_apis::read_only::get_table_by_scope_params param{"eosio.token"_n, "accounts"_n, "inita", "", 10}; eosio::chain_apis::read_only::get_table_by_scope_result result = plugin.read_only::get_table_by_scope(param, fc::time_point::maximum()); @@ -195,7 +196,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_test, validating_tester ) try { produce_blocks(1); // get table: normal case - eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); + eosio::chain_apis::read_only plugin(*(this->control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); eosio::chain_apis::read_only::get_table_rows_params p; p.code = "eosio.token"_n; p.scope = "inita"; @@ -365,7 +366,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_by_seckey_test, validating_tester ) try { produce_blocks(1); // get table: normal case - eosio::chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); + eosio::chain_apis::read_only plugin(*(this->control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); eosio::chain_apis::read_only::get_table_rows_params p; p.code = "eosio"_n; p.scope = "eosio"; @@ -517,7 +518,7 @@ BOOST_FIXTURE_TEST_CASE( get_table_next_key_test, validating_tester ) try { // } - chain_apis::read_only plugin(*(this->control), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); + chain_apis::read_only plugin(*(this->control), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); chain_apis::read_only::get_table_rows_params params = []{ chain_apis::read_only::get_table_rows_params params{}; params.json=true; diff --git a/tests/test_chain_plugin.cpp b/tests/test_chain_plugin.cpp index 4d365e8a02..42925450b7 100644 --- a/tests/test_chain_plugin.cpp +++ b/tests/test_chain_plugin.cpp @@ -10,9 +10,10 @@ #include #include #include -#include -#include +#include #include +#include +#include using namespace eosio; using namespace eosio::chain; @@ -226,7 +227,7 @@ class chain_plugin_tester : public validating_tester { read_only::get_account_results get_account_info(const account_name acct){ auto account_object = control->get_account(acct); read_only::get_account_params params = { account_object.name }; - chain_apis::read_only plugin(*(control.get()), {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); + chain_apis::read_only plugin(*(control.get()), {}, {}, fc::microseconds::maximum(), fc::microseconds::maximum(), {}); auto res = plugin.get_account(params, fc::time_point::maximum())(); BOOST_REQUIRE(!std::holds_alternative(res)); return std::get(std::move(res)); From 7c0e6475d201bb9d56523768ee1c4b7549305b85 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 14:39:43 -0500 Subject: [PATCH 045/151] Remove unneeded default constructors --- libraries/chain/include/eosio/chain/hotstuff.hpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 08135162ec..8c8636b598 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -23,8 +23,6 @@ namespace eosio { namespace chain { struct extended_schedule { producer_authority_schedule producer_schedule; std::map bls_pub_keys; - - extended_schedule() = default; }; struct quorum_certificate { @@ -32,8 +30,6 @@ namespace eosio { namespace chain { fc::unsigned_int active_finalizers = 0; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; bool quorum_met = false; - - quorum_certificate() = default; }; struct hs_vote_message { @@ -50,8 +46,6 @@ namespace eosio { namespace chain { quorum_certificate justify; //justification uint8_t phase_counter = 0; - hs_proposal_message() = default; - uint32_t block_num() const { return compute_block_num(block_id); } uint64_t get_height() const { return compute_height(compute_block_num(block_id), phase_counter); }; }; @@ -59,12 +53,10 @@ namespace eosio { namespace chain { struct hs_new_block_message { block_id_type block_id = NULL_BLOCK_ID; //new proposal quorum_certificate justify; //justification - hs_new_block_message() = default; }; struct hs_new_view_message { quorum_certificate high_qc; //justification - hs_new_view_message() = default; }; struct finalizer_state { @@ -81,8 +73,6 @@ namespace eosio { namespace chain { eosio::chain::quorum_certificate current_qc; eosio::chain::extended_schedule schedule; map proposals; - - finalizer_state() = default; }; using hs_proposal_message_ptr = std::shared_ptr; From 54c9c607e01f5d04a45d50e0d9077d5ece8d2457 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 15:01:47 -0500 Subject: [PATCH 046/151] Removed commented out include --- libraries/chain/controller.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index d6cfd302ec..000658a100 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -27,7 +27,6 @@ #include #include #include -//#include #include #include From 6ded0f3394c830c407e5217e12489eae905274ef Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 15:29:58 -0500 Subject: [PATCH 047/151] Regenerate deep-mind log for new instant_finality protocol feature --- unittests/deep-mind/deep-mind.log | 93 ++++++++++++++++--------------- 1 file changed, 49 insertions(+), 44 deletions(-) diff --git a/unittests/deep-mind/deep-mind.log b/unittests/deep-mind/deep-mind.log index e6531fb652..7c84eacf23 100644 --- a/unittests/deep-mind/deep-mind.log +++ b/unittests/deep-mind/deep-mind.log @@ -34,11 +34,11 @@ DMLOG START_BLOCK 3 DMLOG CREATION_OP ROOT 0 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":0,"consumed":0},"cpu_usage":{"last_ordinal":1262304002,"value_ex":1157,"consumed":101},"ram_usage":2724} DMLOG TRX_OP CREATE onblock da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb4 01e10b5e02005132b41600000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed32329801013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd000000 -DMLOG APPLIED_TRANSACTION 3 da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb403000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b501006400000000000000000000000000000000000000000001010000010000000000ea3055ccfe3b56076237b0b6da2f580652ee1420231b96d3d96b28183769ac932c9e5902000000000000000200000000000000010000000000ea3055020000000000000000000000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed32329801013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd00000000000000000000da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb403000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb403000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df71901006400000000000000000000000000000000000000000001010000010000000000ea3055ccfe3b56076237b0b6da2f580652ee1420231b96d3d96b28183769ac932c9e5902000000000000000200000000000000010000000000ea3055020000000000000000000000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed32329801013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd00000000000000000000da9fbe9042e1bc9bd64d7a4506534d492107a29f79ad671c1fea19ae3fb70eb403000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG RAM_OP 0 eosio code add setcode eosio 180494 177770 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":35325,"consumed":6104},"cpu_usage":{"last_ordinal":1262304002,"value_ex":12732,"consumed":2101},"ram_usage":180494} -DMLOG APPLIED_TRANSACTION 3 03917c562680b415b93db73416ff29230dfbe7ab1ba4d208b46029d01333cd3a03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d0070000fb050000000000000000d8170000000000000001010000010000000000ea30559a90c525172f87bbac0a6378610727f0fe1d7ebe908df973923d29a1606f9a5703000000000000000300000000000000010000000000ea3055030000000000000001000000000000ea30550000000000ea305500000040258ab2c2010000000000ea305500000000a8ed3232fe8a010000000000ea30550000f18a010061736d01000000019d011a60000060037f7e7f0060027f7e0060027f7f0060057f7e7e7e7e0060047f7e7e7e0060017f017f60017f0060037f7f7f017f6000017f60027f7f017f60017e0060027e7f0060047e7e7e7e0060027f7f017e6000017e60047e7e7e7e017f60047f7e7e7f0060037f7f7f0060067e7e7e7e7f7f017f60047f7e7f7f0060037e7e7e0060037e7e7f017f60047f7f7e7f0060027e7e0060047f7f7f7f00028e041803656e761469735f666561747572655f616374697661746564000603656e761370726561637469766174655f66656174757265000703656e760c656f73696f5f617373657274000303656e76066d656d736574000803656e7610616374696f6e5f646174615f73697a65000903656e7610726561645f616374696f6e5f64617461000a03656e76066d656d637079000803656e760c726571756972655f61757468000b03656e760e7365745f70726976696c65676564000c03656e76137365745f7265736f757263655f6c696d697473000d03656e760561626f7274000003656e76167365745f70726f706f7365645f70726f647563657273000e03656e76207365745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000303656e76206765745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000a03656e760c63757272656e745f74696d65000f03656e76146765745f6163746976655f70726f647563657273000a03656e760b64625f66696e645f693634001003656e76095f5f6173686c746933001103656e7611656f73696f5f6173736572745f636f6465000203656e761063757272656e745f7265636569766572000f03656e760a64625f6765745f693634000803656e7606736861323536001203656e760c64625f73746f72655f693634001303656e760d64625f7570646174655f69363400140347460006070007090a08060607070a0a030307070a060715011602160316041603160316030516011603030a0a0a030a17170318181818181818180318181818031818181818081904050170010a0a05030100010616037f014180c0000b7f0041abc3000b7f0041abc3000b070901056170706c79002d090f010041010b092e30323436383a3b3d0ac98001460400101b0b800101037f02400240024002402000450d004100410028028c40200041107622016a220236028c404100410028028440220320006a41076a417871220036028440200241107420004d0d0120014000417f460d020c030b41000f0b4100200241016a36028c40200141016a4000417f470d010b4100419cc000100220030f0b20030b02000b3601017f230041106b2200410036020c4100200028020c28020041076a417871220036028440410020003602804041003f0036028c400b02000b06004190c0000bf50101067f4100210202400240410020006b22032000712000470d00200041104b0d01200110190f0b101d411636020041000f0b0240024002402000417f6a220420016a10192200450d002000200420006a2003712202460d012000417c6a220328020022044107712201450d02200020044178716a220441786a2205280200210620032001200220006b2207723602002002417c6a200420026b2203200172360200200241786a20064107712201200772360200200520012003723602002000101a0b20020f0b20000f0b200241786a200041786a280200200220006b22006a3602002002417c6a200328020020006b36020020020b3301017f411621030240024020014104490d0020012002101e2201450d0120002001360200410021030b20030f0b101d2802000b3801027f02402000410120001b2201101922000d000340410021004100280298402202450d012002110000200110192200450d000b0b20000b0600200010200b0e0002402000450d002000101a0b0b0600200010220b6b01027f230041106b2202240002402002410c6a20014104200141044b1b22012000410120001b2203101f450d00024003404100280298402200450d0120001100002002410c6a20012003101f0d000c020b0b2002410036020c0b200228020c2100200241106a240020000b08002000200110240b0e0002402000450d002000101a0b0b08002000200110260b0500100a000b4e01017f230041e0006b220124002001200141d8006a3602082001200141106a3602042001200141106a36020020012000102a1a200141106a200128020420012802006b100c200141e0006a24000b920901047f02402000280208200028020422026b41074a0d00410041e8c0001002200041046a28020021020b20022001410810061a200041046a2202200228020041086a2203360200200141086a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001410c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141106a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141146a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141186a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001411c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141206a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141246a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141286a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001412c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141306a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141346a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141386a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001413c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141c0006a21040240200041086a220528020020036b41014a0d00410041e8c0001002200228020021030b20032004410210061a2002200228020041026a2203360200200141c2006a21010240200528020020036b41014a0d00410041e8c0001002200041046a28020021030b20032001410210061a200041046a2201200128020041026a36020020000bfa0203017f027e017f230041206b220124002001200029030022024220883c000b200120024228883c000a200120024230883c0009200120024238883c00082001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c000020012002a722043a000f200120044108763a000e200120044110763a000d200120044118763a000c20012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a00042001200041186a29030022023c00172001200029031022034220883c001b200120034228883c001a200120034230883c0019200120034238883c0018200120024220883c0013200120024228883c0012200120024230883c0011200120024238883c001020012002a722004108763a0016200120004110763a0015200120004118763a001420012003a722003a001f200120004108763a001e200120004110763a001d200120004118763a001c200110002100200141206a240020000bf60203017f027e017f230041206b220124002001200029030022024220883c000b200120024228883c000a200120024230883c0009200120024238883c00082001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c000020012002a722043a000f200120044108763a000e200120044110763a000d200120044118763a000c20012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a00042001200041186a29030022023c00172001200029031022034220883c001b200120034228883c001a200120034230883c0019200120034238883c0018200120024220883c0013200120024228883c0012200120024230883c0011200120024238883c001020012002a722004108763a0016200120004110763a0015200120004118763a001420012003a722003a001f200120004108763a001e200120004110763a001d200120004118763a001c20011001200141206a24000bcc0401017f23004190016b220324001018024020012000520d0002400240024002400240024002400240200242ffffb7f6a497b2d942570d00200242ffffffffb5f7d6d942570d01200242808080d0b2b3bb9932510d03200242808080c093fad6d942510d0420024280808080b6f7d6d942520d082003410036028c0120034101360288012003200329038801370300200120012003102f1a0c080b200242fffffffffff698d942550d0120024290a9d9d9dd8c99d6ba7f510d0420024280808080daac9bd6ba7f520d0720034100360264200341023602602003200329036037032820012001200341286a10311a0c070b2002428080b8f6a497b2d942510d0420024280808096cdebd4d942520d062003410036026c200341033602682003200329036837032020012001200341206a10331a0c060b2002428080808080f798d942510d042002428080b8f6a4979ad942520d0520034100360284012003410436028001200320032903800137030820012001200341086a10351a0c050b20034100360254200341053602502003200329035037033820012001200341386a10371a0c040b20034100360274200341063602702003200329037037031820012001200341186a10391a0c030b2003410036024c200341073602482003200329034837034020012001200341c0006a10371a0c020b2003410036027c200341083602782003200329037837031020012001200341106a103c1a0c010b2003410036025c200341093602582003200329035837033020012001200341306a103e1a0b4100101c20034190016a24000b1200200029030010072001200241004710080bd30201077f230041306b2203210420032400200228020421052002280200210641002102024010042207450d00024002402007418104490d002007101921020c010b20032007410f6a4170716b220224000b2002200710051a0b200441003a002820044200370320200220076a2103200441206a41086a210802400240200741074b0d0041004185c1001002200441206a2002410810061a200241086a21090c010b200441206a2002410810061a200241086a210920074108470d0041004185c10010020b20082009410110061a200441186a200336020020042002360210200441146a200241096a3602002004200137030820042000370300200420054101756a2103200441286a2d000021082004290320210002402005410171450d00200328020020066a28020021060b20032000200841ff0171200611010002402007418104490d002002101a0b200441306a240041010b0600200110070b830201057f230041306b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b20044200370328200220076a21030240200741074b0d0041004185c10010020b200441286a2002410810061a2004411c6a200241086a360200200441206a2003360200200420013703102004200037030820042002360218200441086a20054101756a21032004290328210002402005410171450d00200328020020066a28020021060b20032000200611020002402007418104490d002002101a0b200441306a240041010b0d0020002903001007200110290bf70201067f230041a0026b2203210420032400200228020421052002280200210641002102024010042207450d00024002402007418104490d002007101921020c010b20032007410f6a4170716b220224000b2002200710051a0b200441c8006a410041c80010031a2004200236023c200420023602382004200220076a360240200441386a200441c8006a10421a200441086a41086a220320042802403602002004200429033837030820044190016a41086a220820032802003602002004200429030837039001200441d8016a41086a20082802002203360200200441306a2003360200200420003703182004200137032020042004290390012200370328200420003703d80120044190016a200441c8006a41c80010061a200441d8016a20044190016a41c80010061a200441186a20054101756a210302402005410171450d00200328020020066a28020021060b2003200441d8016a200611030002402007418104490d002002101a0b200441a0026a240041010b130020002903001007200120022003200410090b940302067f027e23004180016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b2004420037034820044200370340200442003703502004420037035820042002360234200420023602302004200220076a3602382004200441306a3602702004200441c0006a360210200441106a200441f0006a103f200441086a2203200428023836020020042004290330370300200441e0006a41086a2208200328020036020020042004290300370360200441f0006a41086a20082802002203360200200441286a2003360200200420003703102004200137031820042004290360220037032020042000370370200441106a20054101756a21032004290358210020042903502101200429034821092004290340210a02402005410171450d00200328020020066a28020021060b2003200a200920012000200611040002402007418104490d002002101a0b20044180016a240041010b0d00200029030010072001102c0bfe0301087f230041a0016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b200441c0006a41186a22034200370300200441c0006a41106a22084200370300200442003703482004420037034020042002360234200420023602302004200220076a3602382004200441306a3602602004200441c0006a3602800120044180016a200441e0006a1048200441086a2209200428023836020020042004290330370300200441e0006a41086a220a20092802003602002004200429030037036020044180016a41086a200a2802002209360200200441106a41186a200936020020042000370310200420013703182004200429036022003703202004200037038001200441e0006a41186a22092003290300370300200441e0006a41106a22032008290300370300200420042903483703682004200429034037036020044180016a41186a200929030037030020044180016a41106a200329030037030020042004290368370388012004200429036037038001200441106a20054101756a210302402005410171450d00200328020020066a28020021060b200320044180016a200611030002402007418104490d002002101a0b200441a0016a240041010b5601027f23002202210320002903001007024010042200418104490d00200010192202200010051a20022000100b1a200324000f0b20022000410f6a4170716b220224002002200010051a20022000100b1a200324000bb80501077f230041f0006b220321042003240020022802042105200228020021064100210741002102024010042208450d00024002402008418104490d002008101921020c010b20032008410f6a4170716b220224000b2002200810051a0b200441003602482004420037034020042002360234200420023602302004200220086a360238200441306a200441c0006a10411a200441086a2203200428023836020020042004290330370300200441d0006a41086a2209200328020036020020042004290300370350200441e0006a41086a20092802002203360200200441286a20033602002004200037031020042001370318200420042903502200370320200420003703602004410036025820044200370350200428024420042802406b220341306d21090240024002402003450d00200941d6aad52a4f0d01200441d8006a200310202207200941306c6a36020020042007360250200420073602542004280244200428024022096b22034101480d0020072009200310061a20042004280254200341306e41306c6a22073602540b200441106a20054101756a210302402005410171450d00200328020020066a28020021060b2004410036026820044200370360200720042802506b220741306d210502402007450d00200541d6aad52a4f0d02200441e8006a200710202207200541306c6a36020020042007360260200420073602642004280254200428025022096b22054101480d0020072009200510061a20042007200541306e41306c6a3602640b2003200441e0006a2006110300024020042802602207450d0020042007360264200710220b024020042802502207450d0020042007360254200710220b02402008418104490d002002101a0b024020042802402202450d0020042002360244200210220b200441f0006a240041010f0b200441d0006a1028000b200441e0006a1028000b130002402001102b0d00410041d9c20010020b0b0900200029030010070b870302067f017e23004180016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b2004420037035020044200370348200442003703582004200236023c200420023602382004200220076a3602402004200441386a3602702004200441c8006a360218200441186a200441f0006a1040200441086a41086a2203200428024036020020042004290338370308200441e0006a41086a2208200328020036020020042004290308370360200441f0006a41086a20082802002203360200200441306a2003360200200420003703182004200137032020042004290360220037032820042000370370200441186a20054101756a210320042903582100200429035021012004290348210902402005410171450d00200328020020066a28020021060b2003200920012000200611050002402007418104490d002002101a0b20044180016a240041010bc00203017f017e027f230041c0006b2203240020032001370338200341306a41003602002003427f37032020034200370328200320002903002204370310200320043703180240024002402004200442808080809aecb4ee312001101022004100480d000240200341106a200010452200280230200341106a460d00410041b5c00010020b20032002360208200341106a20004200200341086a1046200328022822050d010c020b2003200236020c2003200341386a3602082003200341106a2001200341086a104720032802282205450d010b024002402003412c6a220628020022002005460d000340200041686a220028020021022000410036020002402002450d00200210220b20052000470d000b200341286a28020021000c010b200521000b2006200536020020001022200341c0006a24000f0b200341c0006a24000b9e0301057f23004180016b2203240020032204200229020037035841002102024010042205450d00024002402005418104490d002005101921020c010b20032005410f6a4170716b220224000b2002200510051a0b200441d0006a4100360200200442003703402004420037034820042002360234200420023602302004200220056a360238200221030240200541074b0d0041004185c1001002200428023421030b200441c0006a2003410810061a2004200341086a360234200441306a200441c0006a41086a220310431a200441086a2206200441306a41086a28020036020020042004290330370300200441e0006a41086a2207200628020036020020042004290300370360200441f0006a41086a20072802002206360200200441286a20063602002004200037031020042001370318200420042903602200370320200420003703702004200441d8006a3602742004200441106a360270200441f0006a200441c0006a104402402005418104490d002002101a0b024020032802002202450d00200441cc006a2002360200200210220b20044180016a240041010bc10201037f20002802002102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a3602002000280200220041086a2102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a360200200041106a2102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a360200200041186a2100024020012802002201280208200128020422036b41074b0d0041004185c1001002200141046a28020021030b20002003410810061a200141046a2201200128020041086a3602000bf30101037f20002802002102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a3602002000280200220441086a2102024020012802002203280208200328020422006b41074b0d0041004185c1001002200341046a28020021000b20022000410810061a200341046a2203200328020041086a360200200441106a2100024020012802002201280208200128020422036b41074b0d0041004185c1001002200141046a28020021030b20002003410810061a200141046a2201200128020041086a3602000be80303017f017e067f2000280204210242002103200041086a2104200041046a2105410021060340024020022004280200490d00410041fbc2001002200528020021020b20022d000021072005200241016a22023602002003200741ff0071200641ff0171220674ad842103200641076a2106200221022007418001710d000b02400240024020012802042208200128020022096b41306d22072003a722024f0d002001200220076b105620012802002209200141046a2802002208470d010c020b0240200720024d0d00200141046a2009200241306c6a22083602000b20092008460d010b200041046a22042802002102200041086a210103400240200128020020026b41074b0d0041004185c1001002200428020021020b20092002410810061a2004200428020041086a220236020041002105420021030340024020022001280200490d00410041fbc2001002200428020021020b20022d000021072004200241016a22063602002003200741ff0071200541ff0171220274ad842103200241076a2105200621022007418001710d000b200920033e02082009410c6a21020240200128020020066b41204b0d0041004185c1001002200428020021060b20022006412110061a2004200428020041216a2202360200200941306a22092008470d000b0b20000b920901047f02402000280208200028020422026b41074b0d0041004185c1001002200041046a28020021020b20012002410810061a200041046a2202200228020041086a2203360200200141086a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001410c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141106a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141146a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141186a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001411c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141206a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141246a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141286a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001412c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141306a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141346a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141386a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001413c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141c0006a21040240200041086a220528020020036b41014b0d0041004185c1001002200228020021030b20042003410210061a2002200228020041026a2203360200200141c2006a21010240200528020020036b41014b0d0041004185c1001002200041046a28020021030b20012003410210061a200041046a2201200128020041026a36020020000ba10203017f017e057f2000280204210242002103200041086a2104200041046a2105410021060340024020022004280200490d00410041fbc2001002200528020021020b20022d000021072005200241016a22083602002003200741ff0071200641ff0171220274ad842103200241076a2106200821022007418001710d000b0240024020012802042207200128020022026b22052003a722064f0d002001200620056b1051200041046a2802002108200141046a2802002107200128020021020c010b200520064d0d00200141046a200220066a22073602000b0240200041086a28020020086b200720026b22074f0d0041004185c1001002200041046a28020021080b20022008200710061a200041046a2202200228020020076a36020020000bf80103017f017e027f230041106b22022400200242003703002002410036020820012903002103024002402001410c6a28020020012802086b2204450d002004417f4c0d01200241086a20041020220520046a36020020022005360200200220053602042001410c6a280200200141086a28020022046b22014101480d0020052004200110061a2002200520016a3602040b20002802002000280204220128020422044101756a21002001280200210102402004410171450d00200028020020016a28020021010b2000200320022001110100024020022802002201450d0020022001360204200110220b200241106a24000f0b20021028000bbf0302077f017e230041206b22022103200224000240200028021822042000411c6a2802002205460d0002400340200541786a2802002001460d012004200541686a2205470d000c020b0b20042005460d00200541686a2802002105200341206a240020050f0b02400240024020014100410010142204417f4c0d0020044181044f0d0120022004410f6a4170716b22022400410021060c020b410041eec00010020b200410192102410121060b20012002200410141a41c000102022052000360230200542003703000240200441074b0d0041004185c10010020b20052002410810061a200541106a2107200241086a21080240200441786a411f4b0d0041004185c10010020b20072008412010061a20052001360234200320053602182003200529030022093703102003200136020c0240024002402000411c6a22072802002204200041206a2802004f0d00200420093703082004200136021020034100360218200420053602002007200441186a36020020060d010c020b200041186a200341186a200341106a2003410c6a105d2006450d010b2002101a0b200328021821012003410036021802402001450d00200110220b200341206a240020050bc40103027f017e017f230022042105024020012802302000460d00410041bdc10010020b024020002903001013510d00410041ebc10010020b20012903002106200328020022032802002207200328020420076b200141106a22071015024020062001290300510d004100419ec20010020b2004220441506a2203240020032001410810061a200441586a2007412010061a20012802342002200341281017024020062000290310540d00200041106a427e200642017c2006427d561b3703000b200524000bfb0101047f230041306b2204240020042002370328024020012903001013510d004100418ac10010020b20042003360214200420013602102004200441286a36021841c000102022032001200441106a105c1a2004200336022020042003290300220237031020042003280234220536020c024002402001411c6a22062802002207200141206a2802004f0d00200720023703082007200536021020044100360220200720033602002006200741186a3602000c010b200141186a200441206a200441106a2004410c6a105d0b2000200336020420002001360200200428022021012004410036022002402001450d00200110220b200441306a24000b960305027f017e017f017e017f230041d0006b2202240020002802002103024020012802002201280208200128020422006b411f4b0d0041004185c1001002200141046a28020021000b200241306a2000412010061a200141046a2201200128020041206a3602004200210441102101200241106a2105410021004200210602400340200241306a20006a2107024020014102490d002006420886200420073100008422044238888421062001417f6a210120044208862104200041016a22004120470d010c020b024020014101460d00410041ffc20010020b200520063703082005200420073100008437030041102101200541106a21054200210442002106200041016a22004120470d000b0b024020014110460d00024020014102490d00200220042006200141037441786a1011200241086a2903002106200229030021040b20052004370300200520063703080b20032002290310370300200341086a2002290318370300200341186a200241106a41186a290300370300200341106a200241106a41106a290300370300200241d0006a24000bba0101047f230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a20034200370300200241086a2102024020044178714108470d0041004185c10010020b20032002410810061a200341106a24000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000bd30201047f230041306b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360224200320023602202003200220046a2205360228200342003703180240200441074b0d0041004185c1001002200341286a2802002105200328022421020b200341186a2002410810061a2003200241086a2202360224024020052002470d0041004185c1001002200341206a41086a2802002105200328022421020b200341176a2002410110061a2003200241016a2202360224024020052002470d0041004185c1001002200328022421020b200341166a2002410110061a2003200241016a3602242003410036021020034200370308200341206a200341086a10431a024020032802082202450d002003200236020c200210220b200341306a24000bbe0201067f0240024002400240024020002802082202200028020422036b20014f0d002003200028020022046b220520016a2206417f4c0d0241ffffffff0721070240200220046b220241feffffff034b0d0020062002410174220220022006491b2207450d020b2007102021020c030b200041046a21000340200341003a00002000200028020041016a22033602002001417f6a22010d000c040b0b41002107410021020c010b20001028000b200220076a2107200320016a20046b2104200220056a220521030340200341003a0000200341016a21032001417f6a22010d000b200220046a21042005200041046a2206280200200028020022016b22036b2102024020034101480d0020022001200310061a200028020021010b2000200236020020062004360200200041086a20073602002001450d00200110220f0b0bd00102047f017e230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a2102024020044108470d0041004185c10010020b200341076a2002410110061a2003290308210620032d0007210420001007200620044100471008200341106a24000bab0202047f047e230041206b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037031841002102200341186a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370318200341186a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a21050240200441787122044108470d0041004185c10010020b200341106a2005410810061a200241106a2105024020044110470d0041004185c10010020b200341086a2005410810061a200241186a2102024020044118470d0041004185c10010020b20032002410810061a200329030021062003290308210720032903102108200329031821092000100720092008200720061009200341206a24000bd30101047f230041206b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b41002102200341186a21050c020b20022004410f6a4170716b220224000b2002200410051a200341186a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a21050240200441787122044108470d0041004185c10010020b200341106a2005410810061a200241106a2102024020044110470d0041004185c10010020b200341086a2002410810061a20001007200341206a24000bc60301047f23004180016b220221032002240041002104024010042205450d00024002402005418004490d002005101921040c010b20022005410f6a4170716b220424000b2004200510051a0b20032004360254200320043602502003200420056a3602582003410036024820034200370340200341d0006a200341c0006a10411a200341106a41086a2204200328025836020020032003290350370310200341e0006a41086a2205200428020036020020032003290310370360200341f0006a41086a20052802002204360200200341386a20043602002003200037032020032001370328200320032903602200370330200320003703702003410036020820034200370300200328024420032802406b220441306d2105024002402004450d00200541d6aad52a4f0d01200341086a200410202204200541306c6a36020020032004360200200320043602042003280244200328024022026b22054101480d0020042002200510061a20032003280204200541306e41306c6a3602040b200341206a20031038024020032802002204450d0020032004360204200410220b024020032802402204450d0020032004360244200410220b20034180016a24000f0b20031028000bc60301067f0240024002400240024020002802082202200028020422036b41306d20014f0d002003200028020022046b41306d220520016a220641d6aad52a4f0d0241d5aad52a21030240200220046b41306d220241a9d5aa154b0d0020062002410174220320032006491b2203450d020b200341306c102021040c030b200041046a21020340200341086a2200420037030020034200370300200341286a4200370300200341206a4200370300200341186a4200370300200341106a4200370300200041003602002002200228020041306a22033602002001417f6a22010d000c040b0b41002103410021040c010b20001028000b2004200341306c6a21072004200541306c6a220521030340200341086a2202420037030020034200370300200341286a4200370300200341206a4200370300200341186a4200370300200341106a420037030020024100360200200341306a21032001417f6a22010d000b2004200641306c6a21042005200041046a2206280200200028020022036b220141506d41306c6a2102024020014101480d0020022003200110061a200028020021030b2000200236020020062004360200200041086a20073602002003450d00200310220f0b0b8a0101037f230041e0006b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360254200320023602502003200220046a360258200341d0006a200341086a10421a20001007200341086a1029200341e0006a24000b950101047f230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a20032903081007200341106a24000bd70303047f027e017f230041f0006b2202210320022400024002400240024010042204450d002004418004490d012004101921050c020b410021050c020b20022004410f6a4170716b220524000b2005200410051a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d0041004185c10010020b200341d0006a2005412010061a200341306a2105410021044200210702400340200341d0006a20046a2108024020024102490d002007420886200620083100008422064238888421072002417f6a210220064208862106200441016a22044120470d010c020b024020024101460d00410041ffc20010020b200520073703082005200620083100008437030041102102200541106a21054200210642002107200441016a22044120470d000b0b024020024110460d00024020024102490d00200320062007200241037441786a1011200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a290300370300200320032903383703182003200329033037031020001007200341106a102c200341f0006a24000be00303047f027e017f230041f0006b2202210320022400024002400240024010042204450d002004418004490d012004101921050c020b410021050c020b20022004410f6a4170716b220524000b2005200410051a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d0041004185c10010020b200341d0006a2005412010061a200341306a2105410021044200210702400340200341d0006a20046a2108024020024102490d002007420886200620083100008422064238888421072002417f6a210220064208862106200441016a22044120470d010c020b024020024101460d00410041ffc20010020b200520073703082005200620083100008437030041102102200541106a21054200210642002107200441016a22044120470d000b0b024020024110460d00024020024102490d00200320062007200241037441786a1011200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a29030037030020032003290338370318200320032903303703100240200341106a102b0d00410041d9c20010020b200341f0006a24000beb0201037f23004180016b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360254200320023602502003200220046a360258200342003703480240200441074b0d0041004185c1001002200328025421020b200341c8006a2002410810061a2003200241086a3602542003410036024020034200370338200341d0006a200341386a10431a200341086a41086a2202200341d0006a41086a28020036020020032003290350370308200341e0006a41086a2204200228020036020020032003290308370360200341f0006a41086a20042802002202360200200341306a2002360200200320003703182003200137032020032003290360220037032820032000370370200341186a2003290348200341386a103d024020032802382202450d002003200236023c200210220b20034180016a24000bbc0102037f017e230041306b22032400200020013602302000420037030020002002280204220428020029030037030020022802002101200428020422042802002205200428020420056b200041106a2204101520032000410810061a20034108722004412010061a2000200129030842808080809aecb4ee31200228020829030020002903002206200341281016360234024020062001290310540d00200141106a427e200642017c2006427d561b3703000b200341306a240020000baa0301057f024002402000280204200028020022046b41186d220541016a220641abd5aad5004f0d0041aad5aad500210702400240200028020820046b41186d220441d4aad52a4b0d0020062004410174220720072006491b2207450d010b200741186c102021040c020b41002107410021040c010b20001028000b20012802002106200141003602002004200541186c22086a2201200636020020012002290300370308200120032802003602102004200741186c6a2105200141186a210602400240200041046a280200220220002802002207460d00200420086a41686a21010340200241686a220428020021032004410036020020012003360200200141106a200241786a280200360200200141086a200241706a290300370300200141686a21012004210220072004470d000b200141186a2101200041046a2802002107200028020021020c010b200721020b20002001360200200041046a2006360200200041086a2005360200024020072002460d000340200741686a220728020021012007410036020002402001450d00200110220b20022007470d000b0b02402002450d00200210220b0b0bdf030b00419cc0000b4c6661696c656420746f20616c6c6f63617465207061676573006f626a6563742070617373656420746f206974657261746f725f746f206973206e6f7420696e206d756c74695f696e646578000041e8c0000b1d7772697465006572726f722072656164696e67206974657261746f7200004185c1000b05726561640000418ac1000b3363616e6e6f7420637265617465206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e7472616374000041bdc1000b2e6f626a6563742070617373656420746f206d6f64696679206973206e6f7420696e206d756c74695f696e646578000041ebc1000b3363616e6e6f74206d6f64696679206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e74726163740000419ec2000b3b757064617465722063616e6e6f74206368616e6765207072696d617279206b6579207768656e206d6f64696679696e6720616e206f626a656374000041d9c2000b2270726f746f636f6c2066656174757265206973206e6f7420616374697661746564000041fbc2000b04676574000041ffc2000b2c756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f72000041000b04b02100000000000000000000000003917c562680b415b93db73416ff29230dfbe7ab1ba4d208b46029d01333cd3a03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b5010000000000ea30556ab602000000000000000000000000 +DMLOG APPLIED_TRANSACTION 3 03917c562680b415b93db73416ff29230dfbe7ab1ba4d208b46029d01333cd3a03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d0070000fb050000000000000000d8170000000000000001010000010000000000ea30559a90c525172f87bbac0a6378610727f0fe1d7ebe908df973923d29a1606f9a5703000000000000000300000000000000010000000000ea3055030000000000000001000000000000ea30550000000000ea305500000040258ab2c2010000000000ea305500000000a8ed3232fe8a010000000000ea30550000f18a010061736d01000000019d011a60000060037f7e7f0060027f7e0060027f7f0060057f7e7e7e7e0060047f7e7e7e0060017f017f60017f0060037f7f7f017f6000017f60027f7f017f60017e0060027e7f0060047e7e7e7e0060027f7f017e6000017e60047e7e7e7e017f60047f7e7e7f0060037f7f7f0060067e7e7e7e7f7f017f60047f7e7f7f0060037e7e7e0060037e7e7f017f60047f7f7e7f0060027e7e0060047f7f7f7f00028e041803656e761469735f666561747572655f616374697661746564000603656e761370726561637469766174655f66656174757265000703656e760c656f73696f5f617373657274000303656e76066d656d736574000803656e7610616374696f6e5f646174615f73697a65000903656e7610726561645f616374696f6e5f64617461000a03656e76066d656d637079000803656e760c726571756972655f61757468000b03656e760e7365745f70726976696c65676564000c03656e76137365745f7265736f757263655f6c696d697473000d03656e760561626f7274000003656e76167365745f70726f706f7365645f70726f647563657273000e03656e76207365745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000303656e76206765745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000a03656e760c63757272656e745f74696d65000f03656e76146765745f6163746976655f70726f647563657273000a03656e760b64625f66696e645f693634001003656e76095f5f6173686c746933001103656e7611656f73696f5f6173736572745f636f6465000203656e761063757272656e745f7265636569766572000f03656e760a64625f6765745f693634000803656e7606736861323536001203656e760c64625f73746f72655f693634001303656e760d64625f7570646174655f69363400140347460006070007090a08060607070a0a030307070a060715011602160316041603160316030516011603030a0a0a030a17170318181818181818180318181818031818181818081904050170010a0a05030100010616037f014180c0000b7f0041abc3000b7f0041abc3000b070901056170706c79002d090f010041010b092e30323436383a3b3d0ac98001460400101b0b800101037f02400240024002402000450d004100410028028c40200041107622016a220236028c404100410028028440220320006a41076a417871220036028440200241107420004d0d0120014000417f460d020c030b41000f0b4100200241016a36028c40200141016a4000417f470d010b4100419cc000100220030f0b20030b02000b3601017f230041106b2200410036020c4100200028020c28020041076a417871220036028440410020003602804041003f0036028c400b02000b06004190c0000bf50101067f4100210202400240410020006b22032000712000470d00200041104b0d01200110190f0b101d411636020041000f0b0240024002402000417f6a220420016a10192200450d002000200420006a2003712202460d012000417c6a220328020022044107712201450d02200020044178716a220441786a2205280200210620032001200220006b2207723602002002417c6a200420026b2203200172360200200241786a20064107712201200772360200200520012003723602002000101a0b20020f0b20000f0b200241786a200041786a280200200220006b22006a3602002002417c6a200328020020006b36020020020b3301017f411621030240024020014104490d0020012002101e2201450d0120002001360200410021030b20030f0b101d2802000b3801027f02402000410120001b2201101922000d000340410021004100280298402202450d012002110000200110192200450d000b0b20000b0600200010200b0e0002402000450d002000101a0b0b0600200010220b6b01027f230041106b2202240002402002410c6a20014104200141044b1b22012000410120001b2203101f450d00024003404100280298402200450d0120001100002002410c6a20012003101f0d000c020b0b2002410036020c0b200228020c2100200241106a240020000b08002000200110240b0e0002402000450d002000101a0b0b08002000200110260b0500100a000b4e01017f230041e0006b220124002001200141d8006a3602082001200141106a3602042001200141106a36020020012000102a1a200141106a200128020420012802006b100c200141e0006a24000b920901047f02402000280208200028020422026b41074a0d00410041e8c0001002200041046a28020021020b20022001410810061a200041046a2202200228020041086a2203360200200141086a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001410c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141106a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141146a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141186a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001411c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141206a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141246a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141286a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001412c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141306a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a2203360200200141346a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141386a21040240200041086a220528020020036b41034a0d00410041e8c0001002200228020021030b20032004410410061a2002200228020041046a22033602002001413c6a21020240200528020020036b41034a0d00410041e8c0001002200041046a28020021030b20032002410410061a200041046a2202200228020041046a2203360200200141c0006a21040240200041086a220528020020036b41014a0d00410041e8c0001002200228020021030b20032004410210061a2002200228020041026a2203360200200141c2006a21010240200528020020036b41014a0d00410041e8c0001002200041046a28020021030b20032001410210061a200041046a2201200128020041026a36020020000bfa0203017f027e017f230041206b220124002001200029030022024220883c000b200120024228883c000a200120024230883c0009200120024238883c00082001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c000020012002a722043a000f200120044108763a000e200120044110763a000d200120044118763a000c20012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a00042001200041186a29030022023c00172001200029031022034220883c001b200120034228883c001a200120034230883c0019200120034238883c0018200120024220883c0013200120024228883c0012200120024230883c0011200120024238883c001020012002a722004108763a0016200120004110763a0015200120004118763a001420012003a722003a001f200120004108763a001e200120004110763a001d200120004118763a001c200110002100200141206a240020000bf60203017f027e017f230041206b220124002001200029030022024220883c000b200120024228883c000a200120024230883c0009200120024238883c00082001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c000020012002a722043a000f200120044108763a000e200120044110763a000d200120044118763a000c20012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a00042001200041186a29030022023c00172001200029031022034220883c001b200120034228883c001a200120034230883c0019200120034238883c0018200120024220883c0013200120024228883c0012200120024230883c0011200120024238883c001020012002a722004108763a0016200120004110763a0015200120004118763a001420012003a722003a001f200120004108763a001e200120004110763a001d200120004118763a001c20011001200141206a24000bcc0401017f23004190016b220324001018024020012000520d0002400240024002400240024002400240200242ffffb7f6a497b2d942570d00200242ffffffffb5f7d6d942570d01200242808080d0b2b3bb9932510d03200242808080c093fad6d942510d0420024280808080b6f7d6d942520d082003410036028c0120034101360288012003200329038801370300200120012003102f1a0c080b200242fffffffffff698d942550d0120024290a9d9d9dd8c99d6ba7f510d0420024280808080daac9bd6ba7f520d0720034100360264200341023602602003200329036037032820012001200341286a10311a0c070b2002428080b8f6a497b2d942510d0420024280808096cdebd4d942520d062003410036026c200341033602682003200329036837032020012001200341206a10331a0c060b2002428080808080f798d942510d042002428080b8f6a4979ad942520d0520034100360284012003410436028001200320032903800137030820012001200341086a10351a0c050b20034100360254200341053602502003200329035037033820012001200341386a10371a0c040b20034100360274200341063602702003200329037037031820012001200341186a10391a0c030b2003410036024c200341073602482003200329034837034020012001200341c0006a10371a0c020b2003410036027c200341083602782003200329037837031020012001200341106a103c1a0c010b2003410036025c200341093602582003200329035837033020012001200341306a103e1a0b4100101c20034190016a24000b1200200029030010072001200241004710080bd30201077f230041306b2203210420032400200228020421052002280200210641002102024010042207450d00024002402007418104490d002007101921020c010b20032007410f6a4170716b220224000b2002200710051a0b200441003a002820044200370320200220076a2103200441206a41086a210802400240200741074b0d0041004185c1001002200441206a2002410810061a200241086a21090c010b200441206a2002410810061a200241086a210920074108470d0041004185c10010020b20082009410110061a200441186a200336020020042002360210200441146a200241096a3602002004200137030820042000370300200420054101756a2103200441286a2d000021082004290320210002402005410171450d00200328020020066a28020021060b20032000200841ff0171200611010002402007418104490d002002101a0b200441306a240041010b0600200110070b830201057f230041306b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b20044200370328200220076a21030240200741074b0d0041004185c10010020b200441286a2002410810061a2004411c6a200241086a360200200441206a2003360200200420013703102004200037030820042002360218200441086a20054101756a21032004290328210002402005410171450d00200328020020066a28020021060b20032000200611020002402007418104490d002002101a0b200441306a240041010b0d0020002903001007200110290bf70201067f230041a0026b2203210420032400200228020421052002280200210641002102024010042207450d00024002402007418104490d002007101921020c010b20032007410f6a4170716b220224000b2002200710051a0b200441c8006a410041c80010031a2004200236023c200420023602382004200220076a360240200441386a200441c8006a10421a200441086a41086a220320042802403602002004200429033837030820044190016a41086a220820032802003602002004200429030837039001200441d8016a41086a20082802002203360200200441306a2003360200200420003703182004200137032020042004290390012200370328200420003703d80120044190016a200441c8006a41c80010061a200441d8016a20044190016a41c80010061a200441186a20054101756a210302402005410171450d00200328020020066a28020021060b2003200441d8016a200611030002402007418104490d002002101a0b200441a0026a240041010b130020002903001007200120022003200410090b940302067f027e23004180016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b2004420037034820044200370340200442003703502004420037035820042002360234200420023602302004200220076a3602382004200441306a3602702004200441c0006a360210200441106a200441f0006a103f200441086a2203200428023836020020042004290330370300200441e0006a41086a2208200328020036020020042004290300370360200441f0006a41086a20082802002203360200200441286a2003360200200420003703102004200137031820042004290360220037032020042000370370200441106a20054101756a21032004290358210020042903502101200429034821092004290340210a02402005410171450d00200328020020066a28020021060b2003200a200920012000200611040002402007418104490d002002101a0b20044180016a240041010b0d00200029030010072001102c0bfe0301087f230041a0016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b200441c0006a41186a22034200370300200441c0006a41106a22084200370300200442003703482004420037034020042002360234200420023602302004200220076a3602382004200441306a3602602004200441c0006a3602800120044180016a200441e0006a1048200441086a2209200428023836020020042004290330370300200441e0006a41086a220a20092802003602002004200429030037036020044180016a41086a200a2802002209360200200441106a41186a200936020020042000370310200420013703182004200429036022003703202004200037038001200441e0006a41186a22092003290300370300200441e0006a41106a22032008290300370300200420042903483703682004200429034037036020044180016a41186a200929030037030020044180016a41106a200329030037030020042004290368370388012004200429036037038001200441106a20054101756a210302402005410171450d00200328020020066a28020021060b200320044180016a200611030002402007418104490d002002101a0b200441a0016a240041010b5601027f23002202210320002903001007024010042200418104490d00200010192202200010051a20022000100b1a200324000f0b20022000410f6a4170716b220224002002200010051a20022000100b1a200324000bb80501077f230041f0006b220321042003240020022802042105200228020021064100210741002102024010042208450d00024002402008418104490d002008101921020c010b20032008410f6a4170716b220224000b2002200810051a0b200441003602482004420037034020042002360234200420023602302004200220086a360238200441306a200441c0006a10411a200441086a2203200428023836020020042004290330370300200441d0006a41086a2209200328020036020020042004290300370350200441e0006a41086a20092802002203360200200441286a20033602002004200037031020042001370318200420042903502200370320200420003703602004410036025820044200370350200428024420042802406b220341306d21090240024002402003450d00200941d6aad52a4f0d01200441d8006a200310202207200941306c6a36020020042007360250200420073602542004280244200428024022096b22034101480d0020072009200310061a20042004280254200341306e41306c6a22073602540b200441106a20054101756a210302402005410171450d00200328020020066a28020021060b2004410036026820044200370360200720042802506b220741306d210502402007450d00200541d6aad52a4f0d02200441e8006a200710202207200541306c6a36020020042007360260200420073602642004280254200428025022096b22054101480d0020072009200510061a20042007200541306e41306c6a3602640b2003200441e0006a2006110300024020042802602207450d0020042007360264200710220b024020042802502207450d0020042007360254200710220b02402008418104490d002002101a0b024020042802402202450d0020042002360244200210220b200441f0006a240041010f0b200441d0006a1028000b200441e0006a1028000b130002402001102b0d00410041d9c20010020b0b0900200029030010070b870302067f017e23004180016b22032104200324002002280204210520022802002106024002400240024010042207450d002007418104490d012007101921020c020b410021020c020b20032007410f6a4170716b220224000b2002200710051a0b2004420037035020044200370348200442003703582004200236023c200420023602382004200220076a3602402004200441386a3602702004200441c8006a360218200441186a200441f0006a1040200441086a41086a2203200428024036020020042004290338370308200441e0006a41086a2208200328020036020020042004290308370360200441f0006a41086a20082802002203360200200441306a2003360200200420003703182004200137032020042004290360220037032820042000370370200441186a20054101756a210320042903582100200429035021012004290348210902402005410171450d00200328020020066a28020021060b2003200920012000200611050002402007418104490d002002101a0b20044180016a240041010bc00203017f017e027f230041c0006b2203240020032001370338200341306a41003602002003427f37032020034200370328200320002903002204370310200320043703180240024002402004200442808080809aecb4ee312001101022004100480d000240200341106a200010452200280230200341106a460d00410041b5c00010020b20032002360208200341106a20004200200341086a1046200328022822050d010c020b2003200236020c2003200341386a3602082003200341106a2001200341086a104720032802282205450d010b024002402003412c6a220628020022002005460d000340200041686a220028020021022000410036020002402002450d00200210220b20052000470d000b200341286a28020021000c010b200521000b2006200536020020001022200341c0006a24000f0b200341c0006a24000b9e0301057f23004180016b2203240020032204200229020037035841002102024010042205450d00024002402005418104490d002005101921020c010b20032005410f6a4170716b220224000b2002200510051a0b200441d0006a4100360200200442003703402004420037034820042002360234200420023602302004200220056a360238200221030240200541074b0d0041004185c1001002200428023421030b200441c0006a2003410810061a2004200341086a360234200441306a200441c0006a41086a220310431a200441086a2206200441306a41086a28020036020020042004290330370300200441e0006a41086a2207200628020036020020042004290300370360200441f0006a41086a20072802002206360200200441286a20063602002004200037031020042001370318200420042903602200370320200420003703702004200441d8006a3602742004200441106a360270200441f0006a200441c0006a104402402005418104490d002002101a0b024020032802002202450d00200441cc006a2002360200200210220b20044180016a240041010bc10201037f20002802002102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a3602002000280200220041086a2102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a360200200041106a2102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a360200200041186a2100024020012802002201280208200128020422036b41074b0d0041004185c1001002200141046a28020021030b20002003410810061a200141046a2201200128020041086a3602000bf30101037f20002802002102024020012802002203280208200328020422046b41074b0d0041004185c1001002200341046a28020021040b20022004410810061a200341046a2203200328020041086a3602002000280200220441086a2102024020012802002203280208200328020422006b41074b0d0041004185c1001002200341046a28020021000b20022000410810061a200341046a2203200328020041086a360200200441106a2100024020012802002201280208200128020422036b41074b0d0041004185c1001002200141046a28020021030b20002003410810061a200141046a2201200128020041086a3602000be80303017f017e067f2000280204210242002103200041086a2104200041046a2105410021060340024020022004280200490d00410041fbc2001002200528020021020b20022d000021072005200241016a22023602002003200741ff0071200641ff0171220674ad842103200641076a2106200221022007418001710d000b02400240024020012802042208200128020022096b41306d22072003a722024f0d002001200220076b105620012802002209200141046a2802002208470d010c020b0240200720024d0d00200141046a2009200241306c6a22083602000b20092008460d010b200041046a22042802002102200041086a210103400240200128020020026b41074b0d0041004185c1001002200428020021020b20092002410810061a2004200428020041086a220236020041002105420021030340024020022001280200490d00410041fbc2001002200428020021020b20022d000021072004200241016a22063602002003200741ff0071200541ff0171220274ad842103200241076a2105200621022007418001710d000b200920033e02082009410c6a21020240200128020020066b41204b0d0041004185c1001002200428020021060b20022006412110061a2004200428020041216a2202360200200941306a22092008470d000b0b20000b920901047f02402000280208200028020422026b41074b0d0041004185c1001002200041046a28020021020b20012002410810061a200041046a2202200228020041086a2203360200200141086a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001410c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141106a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141146a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141186a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001411c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141206a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141246a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141286a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001412c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141306a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a2203360200200141346a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141386a21040240200041086a220528020020036b41034b0d0041004185c1001002200228020021030b20042003410410061a2002200228020041046a22033602002001413c6a21020240200528020020036b41034b0d0041004185c1001002200041046a28020021030b20022003410410061a200041046a2202200228020041046a2203360200200141c0006a21040240200041086a220528020020036b41014b0d0041004185c1001002200228020021030b20042003410210061a2002200228020041026a2203360200200141c2006a21010240200528020020036b41014b0d0041004185c1001002200041046a28020021030b20012003410210061a200041046a2201200128020041026a36020020000ba10203017f017e057f2000280204210242002103200041086a2104200041046a2105410021060340024020022004280200490d00410041fbc2001002200528020021020b20022d000021072005200241016a22083602002003200741ff0071200641ff0171220274ad842103200241076a2106200821022007418001710d000b0240024020012802042207200128020022026b22052003a722064f0d002001200620056b1051200041046a2802002108200141046a2802002107200128020021020c010b200520064d0d00200141046a200220066a22073602000b0240200041086a28020020086b200720026b22074f0d0041004185c1001002200041046a28020021080b20022008200710061a200041046a2202200228020020076a36020020000bf80103017f017e027f230041106b22022400200242003703002002410036020820012903002103024002402001410c6a28020020012802086b2204450d002004417f4c0d01200241086a20041020220520046a36020020022005360200200220053602042001410c6a280200200141086a28020022046b22014101480d0020052004200110061a2002200520016a3602040b20002802002000280204220128020422044101756a21002001280200210102402004410171450d00200028020020016a28020021010b2000200320022001110100024020022802002201450d0020022001360204200110220b200241106a24000f0b20021028000bbf0302077f017e230041206b22022103200224000240200028021822042000411c6a2802002205460d0002400340200541786a2802002001460d012004200541686a2205470d000c020b0b20042005460d00200541686a2802002105200341206a240020050f0b02400240024020014100410010142204417f4c0d0020044181044f0d0120022004410f6a4170716b22022400410021060c020b410041eec00010020b200410192102410121060b20012002200410141a41c000102022052000360230200542003703000240200441074b0d0041004185c10010020b20052002410810061a200541106a2107200241086a21080240200441786a411f4b0d0041004185c10010020b20072008412010061a20052001360234200320053602182003200529030022093703102003200136020c0240024002402000411c6a22072802002204200041206a2802004f0d00200420093703082004200136021020034100360218200420053602002007200441186a36020020060d010c020b200041186a200341186a200341106a2003410c6a105d2006450d010b2002101a0b200328021821012003410036021802402001450d00200110220b200341206a240020050bc40103027f017e017f230022042105024020012802302000460d00410041bdc10010020b024020002903001013510d00410041ebc10010020b20012903002106200328020022032802002207200328020420076b200141106a22071015024020062001290300510d004100419ec20010020b2004220441506a2203240020032001410810061a200441586a2007412010061a20012802342002200341281017024020062000290310540d00200041106a427e200642017c2006427d561b3703000b200524000bfb0101047f230041306b2204240020042002370328024020012903001013510d004100418ac10010020b20042003360214200420013602102004200441286a36021841c000102022032001200441106a105c1a2004200336022020042003290300220237031020042003280234220536020c024002402001411c6a22062802002207200141206a2802004f0d00200720023703082007200536021020044100360220200720033602002006200741186a3602000c010b200141186a200441206a200441106a2004410c6a105d0b2000200336020420002001360200200428022021012004410036022002402001450d00200110220b200441306a24000b960305027f017e017f017e017f230041d0006b2202240020002802002103024020012802002201280208200128020422006b411f4b0d0041004185c1001002200141046a28020021000b200241306a2000412010061a200141046a2201200128020041206a3602004200210441102101200241106a2105410021004200210602400340200241306a20006a2107024020014102490d002006420886200420073100008422044238888421062001417f6a210120044208862104200041016a22004120470d010c020b024020014101460d00410041ffc20010020b200520063703082005200420073100008437030041102101200541106a21054200210442002106200041016a22004120470d000b0b024020014110460d00024020014102490d00200220042006200141037441786a1011200241086a2903002106200229030021040b20052004370300200520063703080b20032002290310370300200341086a2002290318370300200341186a200241106a41186a290300370300200341106a200241106a41106a290300370300200241d0006a24000bba0101047f230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a20034200370300200241086a2102024020044178714108470d0041004185c10010020b20032002410810061a200341106a24000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000b4401037f230022022103024010042204450d00024002402004418004490d002004101921020c010b20022004410f6a4170716b220224000b2002200410051a0b200324000bd30201047f230041306b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360224200320023602202003200220046a2205360228200342003703180240200441074b0d0041004185c1001002200341286a2802002105200328022421020b200341186a2002410810061a2003200241086a2202360224024020052002470d0041004185c1001002200341206a41086a2802002105200328022421020b200341176a2002410110061a2003200241016a2202360224024020052002470d0041004185c1001002200328022421020b200341166a2002410110061a2003200241016a3602242003410036021020034200370308200341206a200341086a10431a024020032802082202450d002003200236020c200210220b200341306a24000bbe0201067f0240024002400240024020002802082202200028020422036b20014f0d002003200028020022046b220520016a2206417f4c0d0241ffffffff0721070240200220046b220241feffffff034b0d0020062002410174220220022006491b2207450d020b2007102021020c030b200041046a21000340200341003a00002000200028020041016a22033602002001417f6a22010d000c040b0b41002107410021020c010b20001028000b200220076a2107200320016a20046b2104200220056a220521030340200341003a0000200341016a21032001417f6a22010d000b200220046a21042005200041046a2206280200200028020022016b22036b2102024020034101480d0020022001200310061a200028020021010b2000200236020020062004360200200041086a20073602002001450d00200110220f0b0bd00102047f017e230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a2102024020044108470d0041004185c10010020b200341076a2002410110061a2003290308210620032d0007210420001007200620044100471008200341106a24000bab0202047f047e230041206b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037031841002102200341186a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370318200341186a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a21050240200441787122044108470d0041004185c10010020b200341106a2005410810061a200241106a2105024020044110470d0041004185c10010020b200341086a2005410810061a200241186a2102024020044118470d0041004185c10010020b20032002410810061a200329030021062003290308210720032903102108200329031821092000100720092008200720061009200341206a24000bd30101047f230041206b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b41002102200341186a21050c020b20022004410f6a4170716b220224000b2002200410051a200341186a2105200441074b0d010b41004185c10010020b20052002410810061a200241086a21050240200441787122044108470d0041004185c10010020b200341106a2005410810061a200241106a2102024020044110470d0041004185c10010020b200341086a2002410810061a20001007200341206a24000bc60301047f23004180016b220221032002240041002104024010042205450d00024002402005418004490d002005101921040c010b20022005410f6a4170716b220424000b2004200510051a0b20032004360254200320043602502003200420056a3602582003410036024820034200370340200341d0006a200341c0006a10411a200341106a41086a2204200328025836020020032003290350370310200341e0006a41086a2205200428020036020020032003290310370360200341f0006a41086a20052802002204360200200341386a20043602002003200037032020032001370328200320032903602200370330200320003703702003410036020820034200370300200328024420032802406b220441306d2105024002402004450d00200541d6aad52a4f0d01200341086a200410202204200541306c6a36020020032004360200200320043602042003280244200328024022026b22054101480d0020042002200510061a20032003280204200541306e41306c6a3602040b200341206a20031038024020032802002204450d0020032004360204200410220b024020032802402204450d0020032004360244200410220b20034180016a24000f0b20031028000bc60301067f0240024002400240024020002802082202200028020422036b41306d20014f0d002003200028020022046b41306d220520016a220641d6aad52a4f0d0241d5aad52a21030240200220046b41306d220241a9d5aa154b0d0020062002410174220320032006491b2203450d020b200341306c102021040c030b200041046a21020340200341086a2200420037030020034200370300200341286a4200370300200341206a4200370300200341186a4200370300200341106a4200370300200041003602002002200228020041306a22033602002001417f6a22010d000c040b0b41002103410021040c010b20001028000b2004200341306c6a21072004200541306c6a220521030340200341086a2202420037030020034200370300200341286a4200370300200341206a4200370300200341186a4200370300200341106a420037030020024100360200200341306a21032001417f6a22010d000b2004200641306c6a21042005200041046a2206280200200028020022036b220141506d41306c6a2102024020014101480d0020022003200110061a200028020021030b2000200236020020062004360200200041086a20073602002003450d00200310220f0b0b8a0101037f230041e0006b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360254200320023602502003200220046a360258200341d0006a200341086a10421a20001007200341086a1029200341e0006a24000b950101047f230041106b22022103200224000240024002400240024010042204450d002004418004490d012004101921020c020b2003420037030841002102200341086a21050c020b20022004410f6a4170716b220224000b2002200410051a20034200370308200341086a2105200441074b0d010b41004185c10010020b20052002410810061a20032903081007200341106a24000bd70303047f027e017f230041f0006b2202210320022400024002400240024010042204450d002004418004490d012004101921050c020b410021050c020b20022004410f6a4170716b220524000b2005200410051a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d0041004185c10010020b200341d0006a2005412010061a200341306a2105410021044200210702400340200341d0006a20046a2108024020024102490d002007420886200620083100008422064238888421072002417f6a210220064208862106200441016a22044120470d010c020b024020024101460d00410041ffc20010020b200520073703082005200620083100008437030041102102200541106a21054200210642002107200441016a22044120470d000b0b024020024110460d00024020024102490d00200320062007200241037441786a1011200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a290300370300200320032903383703182003200329033037031020001007200341106a102c200341f0006a24000be00303047f027e017f230041f0006b2202210320022400024002400240024010042204450d002004418004490d012004101921050c020b410021050c020b20022004410f6a4170716b220524000b2005200410051a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d0041004185c10010020b200341d0006a2005412010061a200341306a2105410021044200210702400340200341d0006a20046a2108024020024102490d002007420886200620083100008422064238888421072002417f6a210220064208862106200441016a22044120470d010c020b024020024101460d00410041ffc20010020b200520073703082005200620083100008437030041102102200541106a21054200210642002107200441016a22044120470d000b0b024020024110460d00024020024102490d00200320062007200241037441786a1011200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a29030037030020032003290338370318200320032903303703100240200341106a102b0d00410041d9c20010020b200341f0006a24000beb0201037f23004180016b2202210320022400024002400240024010042204450d002004418004490d012004101921020c020b410021020c020b20022004410f6a4170716b220224000b2002200410051a0b20032002360254200320023602502003200220046a360258200342003703480240200441074b0d0041004185c1001002200328025421020b200341c8006a2002410810061a2003200241086a3602542003410036024020034200370338200341d0006a200341386a10431a200341086a41086a2202200341d0006a41086a28020036020020032003290350370308200341e0006a41086a2204200228020036020020032003290308370360200341f0006a41086a20042802002202360200200341306a2002360200200320003703182003200137032020032003290360220037032820032000370370200341186a2003290348200341386a103d024020032802382202450d002003200236023c200210220b20034180016a24000bbc0102037f017e230041306b22032400200020013602302000420037030020002002280204220428020029030037030020022802002101200428020422042802002205200428020420056b200041106a2204101520032000410810061a20034108722004412010061a2000200129030842808080809aecb4ee31200228020829030020002903002206200341281016360234024020062001290310540d00200141106a427e200642017c2006427d561b3703000b200341306a240020000baa0301057f024002402000280204200028020022046b41186d220541016a220641abd5aad5004f0d0041aad5aad500210702400240200028020820046b41186d220441d4aad52a4b0d0020062004410174220720072006491b2207450d010b200741186c102021040c020b41002107410021040c010b20001028000b20012802002106200141003602002004200541186c22086a2201200636020020012002290300370308200120032802003602102004200741186c6a2105200141186a210602400240200041046a280200220220002802002207460d00200420086a41686a21010340200241686a220428020021032004410036020020012003360200200141106a200241786a280200360200200141086a200241706a290300370300200141686a21012004210220072004470d000b200141186a2101200041046a2802002107200028020021020c010b200721020b20002001360200200041046a2006360200200041086a2005360200024020072002460d000340200741686a220728020021012007410036020002402001450d00200110220b20022007470d000b0b02402002450d00200210220b0b0bdf030b00419cc0000b4c6661696c656420746f20616c6c6f63617465207061676573006f626a6563742070617373656420746f206974657261746f725f746f206973206e6f7420696e206d756c74695f696e646578000041e8c0000b1d7772697465006572726f722072656164696e67206974657261746f7200004185c1000b05726561640000418ac1000b3363616e6e6f7420637265617465206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e7472616374000041bdc1000b2e6f626a6563742070617373656420746f206d6f64696679206973206e6f7420696e206d756c74695f696e646578000041ebc1000b3363616e6e6f74206d6f64696679206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e74726163740000419ec2000b3b757064617465722063616e6e6f74206368616e6765207072696d617279206b6579207768656e206d6f64696679696e6720616e206f626a656374000041d9c2000b2270726f746f636f6c2066656174757265206973206e6f7420616374697661746564000041fbc2000b04676574000041ffc2000b2c756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f72000041000b04b02100000000000000000000000003917c562680b415b93db73416ff29230dfbe7ab1ba4d208b46029d01333cd3a03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df719010000000000ea30556ab602000000000000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG RAM_OP 0 eosio abi update setabi eosio 180538 44 DMLOG RAM_OP 0 eosio:eosio:abihash table add create_table eosio 180650 112 @@ -46,86 +46,90 @@ DMLOG TBL_OP INS 0 eosio eosio abihash eosio DMLOG RAM_OP 0 eosio:eosio:abihash:eosio table_row add primary_index_add eosio 180802 152 DMLOG DB_OP INS 0 eosio eosio eosio abihash eosio 0000000000ea3055d7abd75d188060de8a01ab2672d1cc2cd768fddc56203181b43685cc11f5ce46 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":41298,"consumed":7136},"cpu_usage":{"last_ordinal":1262304002,"value_ex":24307,"consumed":4101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 78216184577675cf681592f18c754116fdf63576c1fa05b7566dd6ae6fe2ed8003000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d00700008101000000000000000008040000000000000001010000010000000000ea3055e7de58a9939c6e694d3235202685f51b7fab8e82b1f9f96a637dafd9be0998a204000000000000000400000000000000010000000000ea3055040000000000000001010000000000ea30550000000000ea305500000000b863b2c2010000000000ea305500000000a8ed32328a110000000000ea305580110e656f73696f3a3a6162692f312e310019086162695f686173680002056f776e6572046e616d6504686173680b636865636b73756d32353608616374697661746500010e666561747572655f6469676573740b636865636b73756d32353609617574686f726974790004097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d086163636f756e7473197065726d697373696f6e5f6c6576656c5f7765696768745b5d0577616974730d776169745f7765696768745b5d15626c6f636b636861696e5f706172616d65746572730011136d61785f626c6f636b5f6e65745f75736167650675696e7436341a7461726765745f626c6f636b5f6e65745f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6e65745f75736167650675696e7433321e626173655f7065725f7472616e73616374696f6e5f6e65745f75736167650675696e743332106e65745f75736167655f6c65657761790675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f6e756d0675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f64656e0675696e743332136d61785f626c6f636b5f6370755f75736167650675696e7433321a7461726765745f626c6f636b5f6370755f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6370755f75736167650675696e743332196d696e5f7472616e73616374696f6e5f6370755f75736167650675696e743332186d61785f7472616e73616374696f6e5f6c69666574696d650675696e7433321e64656665727265645f7472785f65787069726174696f6e5f77696e646f770675696e743332156d61785f7472616e73616374696f6e5f64656c61790675696e743332166d61785f696e6c696e655f616374696f6e5f73697a650675696e743332176d61785f696e6c696e655f616374696f6e5f64657074680675696e743136136d61785f617574686f726974795f64657074680675696e7431360b63616e63656c64656c617900020e63616e63656c696e675f61757468107065726d697373696f6e5f6c6576656c067472785f69640b636865636b73756d3235360a64656c657465617574680002076163636f756e74046e616d650a7065726d697373696f6e046e616d650a6b65795f7765696768740002036b65790a7075626c69635f6b6579067765696768740675696e743136086c696e6b617574680004076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650b726571756972656d656e74046e616d650a6e65776163636f756e7400040763726561746f72046e616d65046e616d65046e616d65056f776e657209617574686f726974790661637469766509617574686f72697479076f6e6572726f7200020973656e6465725f69640775696e743132380873656e745f747278056279746573107065726d697373696f6e5f6c6576656c0002056163746f72046e616d650a7065726d697373696f6e046e616d65177065726d697373696f6e5f6c6576656c5f77656967687400020a7065726d697373696f6e107065726d697373696f6e5f6c6576656c067765696768740675696e7431360c70726f64756365725f6b657900020d70726f64756365725f6e616d65046e616d6511626c6f636b5f7369676e696e675f6b65790a7075626c69635f6b65790c72657161637469766174656400010e666561747572655f6469676573740b636865636b73756d323536077265716175746800010466726f6d046e616d65067365746162690002076163636f756e74046e616d65036162690562797465730a736574616c696d6974730004076163636f756e74046e616d650972616d5f627974657305696e7436340a6e65745f77656967687405696e7436340a6370755f77656967687405696e74363407736574636f64650004076163636f756e74046e616d6506766d747970650575696e743809766d76657273696f6e0575696e743804636f64650562797465730a736574676c696d69747300030372616d0675696e743634036e65740675696e743634036370750675696e74363409736574706172616d73000106706172616d7315626c6f636b636861696e5f706172616d657465727307736574707269760002076163636f756e74046e616d650769735f707269760575696e74380873657470726f64730001087363686564756c650e70726f64756365725f6b65795b5d0a756e6c696e6b617574680003076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650a757064617465617574680004076163636f756e74046e616d650a7065726d697373696f6e046e616d6506706172656e74046e616d65046175746809617574686f726974790b776169745f776569676874000208776169745f7365630675696e743332067765696768740675696e743136110000002a9bed32320861637469766174650000bc892a4585a6410b63616e63656c64656c6179000040cbdaa8aca24a0a64656c65746561757468000000002d6b03a78b086c696e6b617574680000409e9a2264b89a0a6e65776163636f756e7400000000e0d27bd5a4076f6e6572726f7200905436db6564acba0c72657161637469766174656400000000a0656dacba07726571617574680000000000b863b2c206736574616269000000ce4eba68b2c20a736574616c696d6974730000000040258ab2c207736574636f6465000000ce4ebac8b2c20a736574676c696d697473000000c0d25c53b3c209736574706172616d730000000060bb5bb3c207736574707269760000000038d15bb3c20873657470726f6473000040cbdac0e9e2d40a756e6c696e6b61757468000040cbdaa86c52d50a757064617465617574680001000000a061d3dc31036936340000086162695f6861736800000000000000000000000000000078216184577675cf681592f18c754116fdf63576c1fa05b7566dd6ae6fe2ed8003000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b5010000000000ea3055340100000000000000000000000000 +DMLOG APPLIED_TRANSACTION 3 78216184577675cf681592f18c754116fdf63576c1fa05b7566dd6ae6fe2ed8003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d00700008101000000000000000008040000000000000001010000010000000000ea3055e7de58a9939c6e694d3235202685f51b7fab8e82b1f9f96a637dafd9be0998a204000000000000000400000000000000010000000000ea3055040000000000000001010000000000ea30550000000000ea305500000000b863b2c2010000000000ea305500000000a8ed32328a110000000000ea305580110e656f73696f3a3a6162692f312e310019086162695f686173680002056f776e6572046e616d6504686173680b636865636b73756d32353608616374697661746500010e666561747572655f6469676573740b636865636b73756d32353609617574686f726974790004097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d086163636f756e7473197065726d697373696f6e5f6c6576656c5f7765696768745b5d0577616974730d776169745f7765696768745b5d15626c6f636b636861696e5f706172616d65746572730011136d61785f626c6f636b5f6e65745f75736167650675696e7436341a7461726765745f626c6f636b5f6e65745f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6e65745f75736167650675696e7433321e626173655f7065725f7472616e73616374696f6e5f6e65745f75736167650675696e743332106e65745f75736167655f6c65657761790675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f6e756d0675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f64656e0675696e743332136d61785f626c6f636b5f6370755f75736167650675696e7433321a7461726765745f626c6f636b5f6370755f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6370755f75736167650675696e743332196d696e5f7472616e73616374696f6e5f6370755f75736167650675696e743332186d61785f7472616e73616374696f6e5f6c69666574696d650675696e7433321e64656665727265645f7472785f65787069726174696f6e5f77696e646f770675696e743332156d61785f7472616e73616374696f6e5f64656c61790675696e743332166d61785f696e6c696e655f616374696f6e5f73697a650675696e743332176d61785f696e6c696e655f616374696f6e5f64657074680675696e743136136d61785f617574686f726974795f64657074680675696e7431360b63616e63656c64656c617900020e63616e63656c696e675f61757468107065726d697373696f6e5f6c6576656c067472785f69640b636865636b73756d3235360a64656c657465617574680002076163636f756e74046e616d650a7065726d697373696f6e046e616d650a6b65795f7765696768740002036b65790a7075626c69635f6b6579067765696768740675696e743136086c696e6b617574680004076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650b726571756972656d656e74046e616d650a6e65776163636f756e7400040763726561746f72046e616d65046e616d65046e616d65056f776e657209617574686f726974790661637469766509617574686f72697479076f6e6572726f7200020973656e6465725f69640775696e743132380873656e745f747278056279746573107065726d697373696f6e5f6c6576656c0002056163746f72046e616d650a7065726d697373696f6e046e616d65177065726d697373696f6e5f6c6576656c5f77656967687400020a7065726d697373696f6e107065726d697373696f6e5f6c6576656c067765696768740675696e7431360c70726f64756365725f6b657900020d70726f64756365725f6e616d65046e616d6511626c6f636b5f7369676e696e675f6b65790a7075626c69635f6b65790c72657161637469766174656400010e666561747572655f6469676573740b636865636b73756d323536077265716175746800010466726f6d046e616d65067365746162690002076163636f756e74046e616d65036162690562797465730a736574616c696d6974730004076163636f756e74046e616d650972616d5f627974657305696e7436340a6e65745f77656967687405696e7436340a6370755f77656967687405696e74363407736574636f64650004076163636f756e74046e616d6506766d747970650575696e743809766d76657273696f6e0575696e743804636f64650562797465730a736574676c696d69747300030372616d0675696e743634036e65740675696e743634036370750675696e74363409736574706172616d73000106706172616d7315626c6f636b636861696e5f706172616d657465727307736574707269760002076163636f756e74046e616d650769735f707269760575696e74380873657470726f64730001087363686564756c650e70726f64756365725f6b65795b5d0a756e6c696e6b617574680003076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650a757064617465617574680004076163636f756e74046e616d650a7065726d697373696f6e046e616d6506706172656e74046e616d65046175746809617574686f726974790b776169745f776569676874000208776169745f7365630675696e743332067765696768740675696e743136110000002a9bed32320861637469766174650000bc892a4585a6410b63616e63656c64656c6179000040cbdaa8aca24a0a64656c65746561757468000000002d6b03a78b086c696e6b617574680000409e9a2264b89a0a6e65776163636f756e7400000000e0d27bd5a4076f6e6572726f7200905436db6564acba0c72657161637469766174656400000000a0656dacba07726571617574680000000000b863b2c206736574616269000000ce4eba68b2c20a736574616c696d6974730000000040258ab2c207736574636f6465000000ce4ebac8b2c20a736574676c696d697473000000c0d25c53b3c209736574706172616d730000000060bb5bb3c207736574707269760000000038d15bb3c20873657470726f6473000040cbdac0e9e2d40a756e6c696e6b61757468000040cbdaa86c52d50a757064617465617574680001000000a061d3dc31036936340000086162695f6861736800000000000000000000000000000078216184577675cf681592f18c754116fdf63576c1fa05b7566dd6ae6fe2ed8003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df719010000000000ea3055340100000000000000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241 {"feature_digest":"1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"f3c3d91c4603cde2397268bfed4e662465293aab10cd9416db0d442b8cec2949","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"ONLY_LINK_TO_EXISTING_PERMISSION"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":42039,"consumed":7264},"cpu_usage":{"last_ordinal":1262304002,"value_ex":35882,"consumed":6101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 aa30bc93a59737ce708fd4d691b61d7858bfb309c4cf883e77a6a161b5a4abe503000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055218268a92acd1b24eeaeff3b51b569de14ee151eea2132d748be984aa9535d1405000000000000000500000000000000010000000000ea3055050000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b724100000000000000000000aa30bc93a59737ce708fd4d691b61d7858bfb309c4cf883e77a6a161b5a4abe503000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 aa30bc93a59737ce708fd4d691b61d7858bfb309c4cf883e77a6a161b5a4abe503000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055218268a92acd1b24eeaeff3b51b569de14ee151eea2132d748be984aa9535d1405000000000000000500000000000000010000000000ea3055050000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b724100000000000000000000aa30bc93a59737ce708fd4d691b61d7858bfb309c4cf883e77a6a161b5a4abe503000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99 {"feature_digest":"ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"9908b3f8413c8474ab2a6be149d3f4f6d0421d37886033f27d4759c47a26d944","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"REPLACE_DEFERRED"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":42780,"consumed":7392},"cpu_usage":{"last_ordinal":1262304002,"value_ex":47457,"consumed":8101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 3f12eecaafb41ec5142c6c6d69df767fb8f5183e1e5468aa418bef38a2bdf2bb03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea305513ab6d113ba5b180d6f68e1b67bdea99847550d673a1785e40dfe4faee8ec7c706000000000000000600000000000000010000000000ea3055060000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99000000000000000000003f12eecaafb41ec5142c6c6d69df767fb8f5183e1e5468aa418bef38a2bdf2bb03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 3f12eecaafb41ec5142c6c6d69df767fb8f5183e1e5468aa418bef38a2bdf2bb03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea305513ab6d113ba5b180d6f68e1b67bdea99847550d673a1785e40dfe4faee8ec7c706000000000000000600000000000000010000000000ea3055060000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99000000000000000000003f12eecaafb41ec5142c6c6d69df767fb8f5183e1e5468aa418bef38a2bdf2bb03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f {"feature_digest":"4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"45967387ee92da70171efd9fefd1ca8061b5efe6f124d269cd2468b47f1575a0","dependencies":["ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99"],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"NO_DUPLICATE_DEFERRED_ID"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":43521,"consumed":7520},"cpu_usage":{"last_ordinal":1262304002,"value_ex":59032,"consumed":10101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 39ec55367e4e4d0d6063a5e5aa2aa15d4a1aa1fbe0abe42c9081713ee04e55b103000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea30552267bc3ee69f217c4f0bdbff84c23074f1780839b8adfb17537db55da4a0dc7607000000000000000700000000000000010000000000ea3055070000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000000000000000000039ec55367e4e4d0d6063a5e5aa2aa15d4a1aa1fbe0abe42c9081713ee04e55b103000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 39ec55367e4e4d0d6063a5e5aa2aa15d4a1aa1fbe0abe42c9081713ee04e55b103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30552267bc3ee69f217c4f0bdbff84c23074f1780839b8adfb17537db55da4a0dc7607000000000000000700000000000000010000000000ea3055070000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000000000000000000039ec55367e4e4d0d6063a5e5aa2aa15d4a1aa1fbe0abe42c9081713ee04e55b103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526 {"feature_digest":"e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"a98241c83511dc86c857221b9372b4aa7cea3aaebc567a48604e1d3db3557050","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"FIX_LINKAUTH_RESTRICTION"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":44262,"consumed":7648},"cpu_usage":{"last_ordinal":1262304002,"value_ex":70607,"consumed":12101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 72c5e78f690d5d20ec8c8e12ace2a3b34929099b93f621a8671ae43df821bc5b03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea30550f86c0418ffb919c58d37997594e446d2d98fd38b1ff3849da2c5da410aa331a08000000000000000800000000000000010000000000ea3055080000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000000000000000000072c5e78f690d5d20ec8c8e12ace2a3b34929099b93f621a8671ae43df821bc5b03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 72c5e78f690d5d20ec8c8e12ace2a3b34929099b93f621a8671ae43df821bc5b03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30550f86c0418ffb919c58d37997594e446d2d98fd38b1ff3849da2c5da410aa331a08000000000000000800000000000000010000000000ea3055080000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000000000000000000072c5e78f690d5d20ec8c8e12ace2a3b34929099b93f621a8671ae43df821bc5b03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428 {"feature_digest":"68dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"2853617cec3eabd41881eb48882e6fc5e81a0db917d375057864b3befbe29acd","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"DISALLOW_EMPTY_PRODUCER_SCHEDULE"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":45003,"consumed":7776},"cpu_usage":{"last_ordinal":1262304002,"value_ex":82182,"consumed":14101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 e358ede0d30a5ac5fa03a484a5142b0a38f658e0fb57644adb5b60c94206f9e003000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055659dd999c0cb81c2eea85d3eda39898997e4a9bd57bcebcac06cc25db35e000b09000000000000000900000000000000010000000000ea3055090000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a29742800000000000000000000e358ede0d30a5ac5fa03a484a5142b0a38f658e0fb57644adb5b60c94206f9e003000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 e358ede0d30a5ac5fa03a484a5142b0a38f658e0fb57644adb5b60c94206f9e003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055659dd999c0cb81c2eea85d3eda39898997e4a9bd57bcebcac06cc25db35e000b09000000000000000900000000000000010000000000ea3055090000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a29742800000000000000000000e358ede0d30a5ac5fa03a484a5142b0a38f658e0fb57644adb5b60c94206f9e003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43 {"feature_digest":"ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"e71b6712188391994c78d8c722c1d42c477cf091e5601b5cf1befd05721a57f3","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"RESTRICT_ACTION_TO_SELF"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":45744,"consumed":7904},"cpu_usage":{"last_ordinal":1262304002,"value_ex":93757,"consumed":16101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 60b8a605178774eed85eb65b3ae743e5f3dc9b11d4672e1d00be33a0d21c8dae03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055d209fd21b66b7e1f62b25302fd208120700fb20e0a9a0151d3909e1ca7a98f460a000000000000000a00000000000000010000000000ea30550a0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000000000000000000060b8a605178774eed85eb65b3ae743e5f3dc9b11d4672e1d00be33a0d21c8dae03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 60b8a605178774eed85eb65b3ae743e5f3dc9b11d4672e1d00be33a0d21c8dae03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055d209fd21b66b7e1f62b25302fd208120700fb20e0a9a0151d3909e1ca7a98f460a000000000000000a00000000000000010000000000ea30550a0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000000000000000000060b8a605178774eed85eb65b3ae743e5f3dc9b11d4672e1d00be33a0d21c8dae03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a405 {"feature_digest":"8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a405","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"2f1f13e291c79da5a2bbad259ed7c1f2d34f697ea460b14b565ac33b063b73e2","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"ONLY_BILL_FIRST_AUTHORIZER"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":46485,"consumed":8032},"cpu_usage":{"last_ordinal":1262304002,"value_ex":105332,"consumed":18101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 689db7ff0751fd6025dbc997d9a7ca1fe4e525ee48e55e5fb2aee8403077dd3e03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055fd71f42952743b790fcaa82dabd6a843676b9bd5b91c891fc050f9c41374a35e0b000000000000000b00000000000000010000000000ea30550b0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40500000000000000000000689db7ff0751fd6025dbc997d9a7ca1fe4e525ee48e55e5fb2aee8403077dd3e03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 689db7ff0751fd6025dbc997d9a7ca1fe4e525ee48e55e5fb2aee8403077dd3e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055fd71f42952743b790fcaa82dabd6a843676b9bd5b91c891fc050f9c41374a35e0b000000000000000b00000000000000010000000000ea30550b0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40500000000000000000000689db7ff0751fd6025dbc997d9a7ca1fe4e525ee48e55e5fb2aee8403077dd3e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 2652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25 {"feature_digest":"2652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"898082c59f921d0042e581f00a59d5ceb8be6f1d9c7a45b6f07c0e26eaee0222","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"FORWARD_SETCODE"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":47226,"consumed":8160},"cpu_usage":{"last_ordinal":1262304002,"value_ex":116907,"consumed":20101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 48ed94d5a6fa7dd478278b29bbff0a72bd9d9a5431423ed3f0b1ce393643108303000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea305512250767854476ab3904c7f604b0322bfa91821d01ddb20ecfaaff1beef8e04b0c000000000000000c00000000000000010000000000ea30550c0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000000000000000000048ed94d5a6fa7dd478278b29bbff0a72bd9d9a5431423ed3f0b1ce393643108303000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 48ed94d5a6fa7dd478278b29bbff0a72bd9d9a5431423ed3f0b1ce393643108303000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea305512250767854476ab3904c7f604b0322bfa91821d01ddb20ecfaaff1beef8e04b0c000000000000000c00000000000000010000000000ea30550c0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000000000000000000048ed94d5a6fa7dd478278b29bbff0a72bd9d9a5431423ed3f0b1ce393643108303000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d {"feature_digest":"f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"1eab748b95a2e6f4d7cb42065bdee5566af8efddf01a55a0a8d831b823f8828a","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"GET_SENDER"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":47967,"consumed":8288},"cpu_usage":{"last_ordinal":1262304002,"value_ex":128482,"consumed":22101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 aa192243a78a9d8954a3af3f044207536068d3ad3f7ffb3b7de53b959de190b003000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055063f8bf038af0888c33fcfdd66c2f91fd6b060df73aaa32a1e905b143ceb9ac00d000000000000000d00000000000000010000000000ea30550d0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d00000000000000000000aa192243a78a9d8954a3af3f044207536068d3ad3f7ffb3b7de53b959de190b003000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 aa192243a78a9d8954a3af3f044207536068d3ad3f7ffb3b7de53b959de190b003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055063f8bf038af0888c33fcfdd66c2f91fd6b060df73aaa32a1e905b143ceb9ac00d000000000000000d00000000000000010000000000ea30550d0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d00000000000000000000aa192243a78a9d8954a3af3f044207536068d3ad3f7ffb3b7de53b959de190b003000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d67 {"feature_digest":"4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d67","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"1812fdb5096fd854a4958eb9d53b43219d114de0e858ce00255bd46569ad2c68","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"RAM_RESTRICTIONS"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":48708,"consumed":8416},"cpu_usage":{"last_ordinal":1262304002,"value_ex":140057,"consumed":24101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 a9e581a81302c707c14f5985458d2ef53faf24afacb03115f5cbc17271d7504803000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055f279231a0740adb280f58749e984c932e17897073e9aedc1c33a102df52498430e000000000000000e00000000000000010000000000ea30550e0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d6700000000000000000000a9e581a81302c707c14f5985458d2ef53faf24afacb03115f5cbc17271d7504803000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 a9e581a81302c707c14f5985458d2ef53faf24afacb03115f5cbc17271d7504803000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055f279231a0740adb280f58749e984c932e17897073e9aedc1c33a102df52498430e000000000000000e00000000000000010000000000ea30550e0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d6700000000000000000000a9e581a81302c707c14f5985458d2ef53faf24afacb03115f5cbc17271d7504803000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 4fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2 {"feature_digest":"4fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"927fdf78c51e77a899f2db938249fb1f8bb38f4e43d9c1f75b190492080cbc34","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"WEBAUTHN_KEY"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":49449,"consumed":8544},"cpu_usage":{"last_ordinal":1262304002,"value_ex":151632,"consumed":26101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 4185b6265a360d2bf774af7d82bd837333cfb6b976390dac78c284207b6bbce103000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea305578e423734b3bacaadd9c1864e7a7c612255a9c0d9fcdeba49708ee6b147e13170f000000000000000f00000000000000010000000000ea30550f0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2000000000000000000004185b6265a360d2bf774af7d82bd837333cfb6b976390dac78c284207b6bbce103000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 4185b6265a360d2bf774af7d82bd837333cfb6b976390dac78c284207b6bbce103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea305578e423734b3bacaadd9c1864e7a7c612255a9c0d9fcdeba49708ee6b147e13170f000000000000000f00000000000000010000000000ea30550f0000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2000000000000000000004185b6265a360d2bf774af7d82bd837333cfb6b976390dac78c284207b6bbce103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707 {"feature_digest":"299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"ab76031cad7a457f4fd5f5fca97a3f03b8a635278e0416f77dcc91eb99a48e10","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"WTMSIG_BLOCK_SIGNATURES"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":50190,"consumed":8672},"cpu_usage":{"last_ordinal":1262304002,"value_ex":163207,"consumed":28101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 f6025d888ddcfb8fdfeee18204122f8b7a71908a96ac4e52bf9542ff398b0d4403000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055368a5df8e81472fb54f3424401fba4956a6e0737806b4f642b2d7014cf66fc2c10000000000000001000000000000000010000000000ea3055100000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670700000000000000000000f6025d888ddcfb8fdfeee18204122f8b7a71908a96ac4e52bf9542ff398b0d4403000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 f6025d888ddcfb8fdfeee18204122f8b7a71908a96ac4e52bf9542ff398b0d4403000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055368a5df8e81472fb54f3424401fba4956a6e0737806b4f642b2d7014cf66fc2c10000000000000001000000000000000010000000000ea3055100000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670700000000000000000000f6025d888ddcfb8fdfeee18204122f8b7a71908a96ac4e52bf9542ff398b0d4403000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071 {"feature_digest":"c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"69b064c5178e2738e144ed6caa9349a3995370d78db29e494b3126ebd9111966","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"ACTION_RETURN_VALUE"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":50931,"consumed":8800},"cpu_usage":{"last_ordinal":1262304002,"value_ex":174782,"consumed":30101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 116b232e8995b25d7bab8c5134bc993bcd84e72bc35d0b27fe723d7d25e98ac703000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea30552acd5ab1218225e0cc0a013d8e86b58cfc4d998058708fb1eb0116c1124f7c7f11000000000000001100000000000000010000000000ea3055110000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead4507100000000000000000000116b232e8995b25d7bab8c5134bc993bcd84e72bc35d0b27fe723d7d25e98ac703000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 116b232e8995b25d7bab8c5134bc993bcd84e72bc35d0b27fe723d7d25e98ac703000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30552acd5ab1218225e0cc0a013d8e86b58cfc4d998058708fb1eb0116c1124f7c7f11000000000000001100000000000000010000000000ea3055110000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead4507100000000000000000000116b232e8995b25d7bab8c5134bc993bcd84e72bc35d0b27fe723d7d25e98ac703000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 5443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4 {"feature_digest":"5443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"70787548dcea1a2c52c913a37f74ce99e6caae79110d7ca7b859936a0075b314","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"BLOCKCHAIN_PARAMETERS"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":51672,"consumed":8928},"cpu_usage":{"last_ordinal":1262304002,"value_ex":186357,"consumed":32101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 11a09bc0cc023daf656af6dadf37577a9d4c0cea8020c1d007a2c3d6dc1e52c103000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055db17f5e8a451e3814885ec6d61c420ac422f1e0de77043c9024e592b64f8bd1412000000000000001200000000000000010000000000ea3055120000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000000000000000000011a09bc0cc023daf656af6dadf37577a9d4c0cea8020c1d007a2c3d6dc1e52c103000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 11a09bc0cc023daf656af6dadf37577a9d4c0cea8020c1d007a2c3d6dc1e52c103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055db17f5e8a451e3814885ec6d61c420ac422f1e0de77043c9024e592b64f8bd1412000000000000001200000000000000010000000000ea3055120000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000000000000000000011a09bc0cc023daf656af6dadf37577a9d4c0cea8020c1d007a2c3d6dc1e52c103000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99 {"feature_digest":"bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"d2596697fed14a0840013647b99045022ae6a885089f35a7e78da7a43ad76ed4","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"GET_CODE_HASH"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":52413,"consumed":9056},"cpu_usage":{"last_ordinal":1262304002,"value_ex":197932,"consumed":34101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 76bcbbd871a26403befd2ebf5491d6b84ded9f29cb95bfd54ca6ec46b1dfad5903000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055693240e7063adb7478594592f8a6e6cb76e33cabc605272575b687e3a0fa5f5e13000000000000001300000000000000010000000000ea3055130000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000000000000000000076bcbbd871a26403befd2ebf5491d6b84ded9f29cb95bfd54ca6ec46b1dfad5903000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 76bcbbd871a26403befd2ebf5491d6b84ded9f29cb95bfd54ca6ec46b1dfad5903000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055693240e7063adb7478594592f8a6e6cb76e33cabc605272575b687e3a0fa5f5e13000000000000001300000000000000010000000000ea3055130000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000000000000000000076bcbbd871a26403befd2ebf5491d6b84ded9f29cb95bfd54ca6ec46b1dfad5903000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40 {"feature_digest":"d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"8139e99247b87f18ef7eae99f07f00ea3adf39ed53f4d2da3f44e6aa0bfd7c62","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"CONFIGURABLE_WASM_LIMITS2"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":53154,"consumed":9184},"cpu_usage":{"last_ordinal":1262304002,"value_ex":209507,"consumed":36101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 1948411767455fe23b05b44fe5fb737422ce3831a41f2c68064990fd6f52fdaf03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055a40aa97866a6e0814065142f7d1038aaccb2e8a73661f6554c415c331ab8ec8b14000000000000001400000000000000010000000000ea3055140000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40000000000000000000001948411767455fe23b05b44fe5fb737422ce3831a41f2c68064990fd6f52fdaf03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 1948411767455fe23b05b44fe5fb737422ce3831a41f2c68064990fd6f52fdaf03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055a40aa97866a6e0814065142f7d1038aaccb2e8a73661f6554c415c331ab8ec8b14000000000000001400000000000000010000000000ea3055140000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40000000000000000000001948411767455fe23b05b44fe5fb737422ce3831a41f2c68064990fd6f52fdaf03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc {"feature_digest":"6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"68d6405cb8df3de95bd834ebb408196578500a9f818ff62ccc68f60b932f7d82","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"CRYPTO_PRIMITIVES"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":53895,"consumed":9312},"cpu_usage":{"last_ordinal":1262304002,"value_ex":221082,"consumed":38101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 3cea935e0deaa090b14d4ee01f3fee31a1c426779f1c32840aefaa99cb83ec5f03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea30555705a61c2ae1877963ee8e857abb78d2975071d25ce32f1235b4d4803967a9fa15000000000000001500000000000000010000000000ea3055150000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc000000000000000000003cea935e0deaa090b14d4ee01f3fee31a1c426779f1c32840aefaa99cb83ec5f03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 3cea935e0deaa090b14d4ee01f3fee31a1c426779f1c32840aefaa99cb83ec5f03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30555705a61c2ae1877963ee8e857abb78d2975071d25ce32f1235b4d4803967a9fa15000000000000001500000000000000010000000000ea3055150000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc000000000000000000003cea935e0deaa090b14d4ee01f3fee31a1c426779f1c32840aefaa99cb83ec5f03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b {"feature_digest":"35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"e5d7992006e628a38c5e6c28dd55ff5e57ea682079bf41fef9b3cced0f46b491","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"GET_BLOCK_NUM"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":54636,"consumed":9440},"cpu_usage":{"last_ordinal":1262304002,"value_ex":232657,"consumed":40101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 04ba316cf9ddd86690833edc0f4548f8c07f0d66c09dca029b0a1fb96f16c62803000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea3055302a2f1713925c939a997367c967b457bfc2c580304f9686b1de22fc5946e40616000000000000001600000000000000010000000000ea3055160000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000000000000000000004ba316cf9ddd86690833edc0f4548f8c07f0d66c09dca029b0a1fb96f16c62803000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 +DMLOG APPLIED_TRANSACTION 3 04ba316cf9ddd86690833edc0f4548f8c07f0d66c09dca029b0a1fb96f16c62803000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055302a2f1713925c939a997367c967b457bfc2c580304f9686b1de22fc5946e40616000000000000001600000000000000010000000000ea3055160000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000000000000000000004ba316cf9ddd86690833edc0f4548f8c07f0d66c09dca029b0a1fb96f16c62803000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG FEATURE_OP PRE_ACTIVATE 0 98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88 {"feature_digest":"98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"01969c44de35999b924095ae7f50081a7f274409fdbccb9fc54fa7836c76089c","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"BLS_PRIMITIVES"}]} DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":55377,"consumed":9568},"cpu_usage":{"last_ordinal":1262304002,"value_ex":244232,"consumed":42101},"ram_usage":180802} -DMLOG APPLIED_TRANSACTION 3 793b276fb55f2f81cbdcfcaf882555ea5dde340f80c16e5dc652ffad52eea87c03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50100d007000010000000000000000080000000000000000001010000010000000000ea30553a97dc6254ea785e8c6ee5994044fae975bfc8ef1916a24b476a984724cc5cf017000000000000001700000000000000010000000000ea3055170000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e8800000000000000000000793b276fb55f2f81cbdcfcaf882555ea5dde340f80c16e5dc652ffad52eea87c03000000023b3d4b01000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b50000000000000000 -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":2,"value_ex":0,"consumed":0},"average_block_cpu_usage":{"last_ordinal":2,"value_ex":833334,"consumed":100},"pending_net_usage":9568,"pending_cpu_usage":42100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1049625,"virtual_cpu_limit":200200} -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":79733334,"consumed":9568},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":351659723,"consumed":42101},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} -DMLOG ACCEPTED_BLOCK 3 03000000030000000200000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100012d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b0200000000000000010000000000ea305503000000010000000000ea305502000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010000000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b5023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e841639eb3a733e9536932b85f63002945d82e25a0ef948f220ba098df51ab2f5d9d5fc55180118b2a44ae7b7ad158b7de8fee6df8ac1c5afd3681c5b11460ac9600000000000000205965a329efe657efedb21975c97dab14e1d8cfbdcd9492177294fcfe876d7c0a1ffb656f523795bea8035bb945520efcb50606d38965fd0fc8c94a2a99f28e510000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0001023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e841639eb3a733e9536932b85f63002945d82e25a0ef948f220ba098df51ab2f5d9d5fc55180118b2a44ae7b7ad158b7de8fee6df8ac1c5afd3681c5b11460ac9600000000000000205965a329efe657efedb21975c97dab14e1d8cfbdcd9492177294fcfe876d7c0a1ffb656f523795bea8035bb945520efcb50606d38965fd0fc8c94a2a99f28e511500d0070000fb05010100203b7de491b51d3d74624078bc2c5dc4420985f0350afb6923a5585b5621750c9f126d7cff0efeade2068c7b618fc754b2abb5bff8cdb9bd0ecb4432b72ae1ed380100a82f78daed5c7b8c5ce755ff1ef7357b67e3ebc6d94c3609f9e662d0b8a4659bb8eb2575dbbddbc476694b9cca2dfea3b0bbd99d647776bdbb9e1da70e0adead081045158a7894b6405524a4d21424545aa8cacb0d0815a94891fa20414284ff2a025511a245ad54737ee77cf7ceeccb71f09a87545b9e7be77b9cef7ce79cef3cbf71f44fe94f1bf5d03d9f1951f447e343fdf3d87be873f2879efef473830dea77fff59e7bbef7f440d3bfd197d9f57368d1bfa54767949ab11b9736d48cd9b8840f7a0b372ed11f35136cf0436fe80dfac0b80dbc2afa67f84d6306e6063201ad97a8ff9234d00880f033d54c84469e48cd68b03c8b3ea54dd0909531c1fc52d0b0ed95c70e2dae4f3fd29eed5de8b6a767e77a8b8fcdf6daf32a42d7cd6bdd76d9548e51317aeaedd5f5c5d5e9d9f5f576b7a72c9aa273ed73ebed9e4af025c3b4d595e9f9d9deecf4fae2cfb4558d9b09defcf4409f1a2aa7cead3d2e53ebddf6f90b8b40e6426f41a568ba89e04eaf75171f5b5c6e3f4ac8d519393476dbebab17ba73ede9e5c5738bbd75358c9e70f6e155c24ae17d44a6aeaeadaeb7e7f1327f61aedd5d5737a1d3a1f3e1e5d5b9a5b985d9c595e9b5d9eeecb9768ffae9756e8956e29db9475f6918efa23e77a1db6daff4a67b8be7daea00d316339982ed81b579743afff0f4238b2bf3d38be347558696da34d17361b9b778af3a88ef0707693c3db73adf56868958aed36dcfb5097257d61a2280580ef09890d1fac2ec3d6f1c57af61e4a877bdb74a6445ffcd681aa6a60b6bf3e02dda0ed993275414abb8369444511c0f0d594b9f517c8b1e31237624a07ff4371cd123d60e51efd0adb7da86ff63ab8f46725b10ea353d34145aad7434623774b17959a51baaf8d45f568fb8a6c3d9b5b5e5c7d5eb6a07b42a745a7bfdd83d47c727ee7bd39b87fe66539f0854767bbaa9b5dd3093f2d7a9078655417f5be683f4a5c81ecb752737e3f44d5a9f9cccad539d22ee1417cfe76a9c1a9c29b29e53ef1ad64e4faa62e3c4b0a9dbb45007e81ff5e90e663b4d2fe83d39aca9bdf8cdcb2a33ce1e489d4d8d4ac7b5def8415a6e29a755c64d9d66d262f59651832ba175dc6cd2f3ad0a40313352c533b4f3ffd03ada2854d3601718b7043ccf3b757258611fef0076d96d07d2ecce62649cc0127ae5968b8d4e1e38ddc96ecbb17da75c405b74f67c6e4ed034553cd1c92da19207457c3ed70f0c1b0c21ac685a71b19387d4d78c9c75da192c1c776901daf9131d02648088f62d173b2e62184ec68434c5f29bca465367881c84970c54f4d1c22c80549d0a2430a126fe9ede4b742b469a9637a28be0ed843e6191fd00d024d49de6bd366d0a5a6777d2dc74429b0dde36f5df9e6bec7a5859225a9339fce1c9dc60ae39a894d39e26292146a426345d7a93f272c2484b6b9e2e1154e1a0398c01a6a8778011febd839629d7b3d95d34d54c62415e4c31a2584ca6381a31acea26051d200bf4245168a23feb1ca6d5d2043cd2d9e1eda8f8f61f4e43950da9f42744a85e22fae9c3a08b2e5e0021137ecde82da8ded0adb2d78ef257a75be822622d65756a7949d1bae92fd774c0846b1104fa0872b354c43fcee7e5eb2cceaa08c0b2a62194695a9245a3dc961b6c411509c9112f456fcd80799088f838bb54d8415018cf5c23410b00c783082a10f50e84dded3abb44840118013088481f4a76fd881cda17441ad78fc81dfb8288bb7e440eef0b22adeb47e4ee7d4164ecfa1139ba2f884c5c3f22c7f70591cb6a174cf45e9898014c4c05e33982a10750d17ba2a2050223a0592d1118361ae9778cd51be612eb3957aa3975c4aadc4cb9a78eab14d660aa456f43fc36466f357e9ba03728426c01e32d8f870db33cdef01bc66b7ec378b62d9fc883fbd4017a0b8ae4b1fbd44dfc96d1db30bf35e8ad8e193c2eaec645d5b8b01a17f0fa0d5edf1c57b70aee99c7e5f60a97d10a97db2a5c1abc0b8cbbb9dae36baa3d1eacf69809ce8a9118e10581c42db234bd1d1264d57dea2e2107b5fd4035eece6adc1d6459c844b286602bf4adefd3fe7f92f6da533efd522076fd194daed5619535e0fa38f56e78155bff121a57aefcf1b77ee7d73ffde2d44f929380af57ae7cf6db5fc35720b9b9b9f9fca7fff04f3e72cf43c356be5efe95ef50ef43c3817cddfc230c7ef770e22c7c910f12ba05b9544fd1d3d923f6297dccb263414ecb8f8ed693d42f71e55b1f7e71ea3dbcc4339f7cf1c57ff8e047bef6f98d3ed0bfffbddfa0efef1e8e05ea3c3dc8c59e119833c76c4b409205c8de305a8f539ef639d94705e5437ffbf257805a244096e9419a6541802c1cb3ce03719decded17a94fab537bffde13e10c0fc28808402e4494c08c8c5f6fbdba4fd251e4ed2c9de385a0f531979861ee1b8392de34e1fb3137ed844273b365a0ffcb01e3da271b326c3d68ed9861fd6e8643f365ab77ed83be9118f9b5332ecd4313be98791a20538e3c73d013cc6cd451977f198cdfcb8ac931d1fad6b3fec7df4a88d9bb332ecec313be6878d75b2b78c52f891dd415f9ed190a6d7283eb3194e0bf99b27b324fdb2d131046c8ce4ab19389231e8eea0198a568f24ccc8823c7e4064cec5c507d8f58eb3db9a86d1a0a6039d62ed3cbbc37007e32c240f3f2848d65b2e98526010b5769ab010ae038f30f1b0e277b025f8f92fc012a09310635fd260540df077b6d2bce4647f5eea12572b34fae9bc53d4007b414c1f3719351cc2e45a47da98c714f14094031716fa8220d5eabc4ea926751db1ae09479bbacec3d7e6082462fb1461abca25c5157dde4507b51a2086c978c36344650a3d2378e671fa73468757a36d79743d753d30ed296b52d09ec5612f0283b22d4fd91dd44c795b25e102f218997a4c0750d45614c9842289d0ac0145dae9d3e6886dbd0245a283666f5a0cf7652e3b927edb50e84a24f9b8b911f2f6450ad6157d667654f6725c1e13781095c6095c40a756866653a3bc550e555cd032934211daf1045303a7069d09efb9ea4c8ed96760595ee05e97205a1662d29e4bb22a1c7fa6ae9359cfe89cb9c55d2f6881ee71268c99452f700b562d5b1a1523aec20199181db4bb70e1e346d870f3e0d1c79cac96feaa3511197562c7a6be91227a4a1e93f2382d8fb3c29aa3f218ab38045e819050a478bb8c2816e738036dbe496c7b2b734d58365171658c8f34c2d75d5846ebcdc8eced1c6b0d722c138e3564d24cae847bf4581304060ec559728fe871baa9f138454a891e93cda1abf069c8c125c2790976e1d4a6de7960ee4ebf6775c207e6867108142639236748b4227fcf8884fefb560ebe02cf66fa3cdbd4b229614a764ab856bb1ad78840bb706d53ced910b85613ae65c0d8d5ae81718cc54bb2c31a2ca4eaaf98418892b289d978cc2ec8db647f6dac54cd430309821d9c450e083949b2b45f31bbb673bbb9f7b9f5d2f05e4e35e586844ea48239adfc6095dd46019b2246227596a5a3900f24d5c897ec33dbed18927e2e14b3ff4db5b71e8e2b5d9c94ba38f1eb267d5d9c6c93aaa4b4fd7071f6949a44a4060a93c5252b46af76aa9f17f9a8ed38d5a72be161d1b986537d7a40386604cfb395626a99fbd91010518ab173cd9a77ad2db8572bbef6ec575ffbe030ab7ea44c3397c7d43ab6ec7d8b182e223fcef421e535c0d2a77032e9f85b56ebe8815339b682d93966a4d726348cef82e03b431009d0e9a53c06b221840833428f28fca9af13a231231a6e4174461ef38209a000d1b08f682888f2bc15993a2f324be42e6596e6cd88d6f1d0e22c4fa5fdf440fb99b23d19907119c6f957efacdd4fed792a6a1ab27f2015ce672d957a25426f3763619dfd083b3a2f3e074727ad952a33fd4598347de34ddae92d7af1ecdede06fb1ba52dfb22f46243ccbad8b2c957f040763767c99ee6ec2a0ec8cc80ffb1b6c5b5d8d59c5d456f95562cbc8a15bb8c8481bec479f2cb8a83576477103b2134297833766a03e859f16345c3e5014e2ce144f8fbe347e87338f7d17ff9cc37de40bccf5038390595c4d11069b50772d522cd826f2758303e7b993d600b7e247ed49492c8ee0436d4cac3615d2f87d4113d31a3127ecb3a651878d20f7e6058a7a20b8abb3b790492d3493b816202e9da850e1020c1715cd2e19ac0034c1412e8900b3329c7b818a4a038c326b5442e947a482ee11feb6eff967ecc4af4b0a93df57212ab2306e25629e6b054cca1e742d857cce136e90dbd62862e15511a70ca4eeda2a343d6d1c66ba3ad815acb1c45be8e75370825dac2727c717440afb364676ff3ca3de21e7a1b14e6ad2e40eca2bd1db718648f2a151f5d9be326fa1af179c04a964f23407ad373ff00fdbc66e20a9868a6e24b34d070054ab45329e15f30da6e38613b54129f42944b2cca25c1d2568a599fe40cc08a40086639cbca8bf9c04cb15c21c6dd3f90287bec23b44687a34186a6010df5a3dc6e83a6fb395d55ca871ec8e932b4f4dff50d2261b00709d51e2095b84c7b8084d0ecdfa6bf6e593346bcf1a069a6147c3bae9271dabb19d2f18e2ca7f470d0d4db7989efc2d471029d4b6e48579071e69a73cee2097b75459d7711f21379d4fbfd27096e54c49d664487980c1249ee79d2435ea9f20e12d9526d891c083a7af613b97950aaaa2e5ecadeeb7bcb8de5c949d699d0facebc0b03a983cc81613726c1eee85b728274a564f0835229d2eeb4f5cbd2495adaa14e7857b52a5bc14dd007466aba21a8e469a2b7d124d84a934068120dd224649a18a189014d42170dd0049ed95b0cb248f5bedcb868a9703bd0447291c8da1c40b3e93940be207c54a4a6b886bc7b117510e2401155977b7f1545d441506511065af8da8aa8bb2162b13bfbaa8ba8af0e9143fb8248e3fa11b9635f1071d78fc8e17d41a475fd88dcbd2f888c5d3f2247f7059189eb47e4f8be20b27b11752f4caeb188ba072aba84b05b11f5b7c52f0ff7d1fa243badcfa0a68d5cb2cdfa88ed89c5ba180a3b617822313ce4122f650f55db492aa32ac3c5b925e55d591f52c61c4103346f04d4499660a128307e701712259ca6a0686e2bb738620389fe53f74397cc27502417c677740825f24bab6b48755e104ec1521e88c7b8f1ce61d6e6e46052e81dba402e3489b3cf8fa03f5130266727d7127d87f065450042870b65e4efa896783641cea40b386e534211cd496d89d4789ce65d6a7642602ea55261d877e1a00417a5b0469efa6b46c81821b6fe0b6b62899edd12a79ce47a13416de4108f3b1855443db8d34456556e6d69dc1c433585c2a0f0a4bfcf147074c48d4027e4ea1c9132aceea269dcb2cb0ee54c30d0ed0301b22bf0edfa910ba49183f2e21b12d20588700a0d3bcc63b343a374ba98ce0a914bc8ac629a6cad8684a5810d61c3622925253cf062a7b86bcbd8d82585e3b1a0d551445308dce98108b526112af5d4ab6b75779010321fe9dd61c70f725aa32665158d143697eb10a2b01cc41c82e32d92405471e94a3e90612401c97eca45083c25b8268fb4d1d41e0ce8076632174bd2a67fa5ad2106a2649c079c11d2888b9504c57fc69b03ba4896dcfc1037be2c3b66998e24f0e18f983d667203d9e6e771760b4d8c789c4cfcd873c20fe2dfe94e19df97c5a6b314ac09050981a3ac1d5bd9ad0c0195f7337251b13375c94553fa09faf8d9f7de4e6c232e51b0fa5d4d7e93d4cd82c39c1c3a46b84cf2da25da4ffb1217d21d874a0a071c1712754422ac5c05e864ef1b958188092d5f02909091a01ecd43cf46f60724b28fd9aa7b26c6583e41264cea100a706249b344b44b6622b49296b48eeb94c50a30904f218e9b5c4f844a75c8b130982d4c948a59fa211b0a0b858d14ae8b0ae228c9ee0c4228a4b96bb72004210dc270e5d930600b1c3026c54f683635ab00d6fa688af860cb443a244c1583c0389a4a7e01d9bc3728f5641e4c4d3cf524498b2e363ad80cf5b1f9206340d0ab2081149a08de95e7fc098c40c9b084430c670cf840c2c30f80c1001c72a3194cc61aa744850e3d04b1b03d3ab8d9413ec822bd068f000b0550d7b21ea77848e6d0820405be34e44ba3c3bb979b21d294f9a6ac6c324898105f3eef85321bd08c03a944affa37399518f854a264b612a46b78e9665837e93605c7df919d97b17e9c682fbe3dbc5d7dd9d216f910179773b795c36d3596d57b7a3f85d95244a87095c41ae3ab3cbe7a2fd4522e197c1fc80d02f26553a9bb6d92b5975c9529ea3da1226175581e8e9d003afca4be5a223c8d1dd6b1ca4d86d089879b7c07a5515d1e6079e220f730fc4f674e6e99ea7c4a6fcbec5b315b97b3f59eb3ab0923db26f00ea026b3fed1701dc9cabe6d5492748924e97c0ed7882d6435fae7b86830703b4af160f1a12cd9b407799af2ae171cad3c821f620a5c698a59f511d988b0c5f7a8016e3f291dc2ab0777d1456fbf1dd503b80a996be23700e23d231d6c71ef05b7b3011d3bf7fefb062960728e82342d8b6b900cc5e50dbec311c38292e1586a4afa350f91f328e15902d5b4151ce636bcf6509cd8a85526bf902f5e62d5e00b4f7cc58ebdddca313462bd02c9e921b5ca387a6374204d9fd7261057f07f5de10d68ba6d6a8ec28b4a668ed804fecbeb540c5394c5d81d5f712a95e0a70ced28d8eedc5edb8e1a7e478d6bd851c38f7ba51d855e77e73bb7c585403f322b4766db062503831a25811a7bd801efdd8148311e194556f468346b4cab1ae221176535ef4aa65ff6d6eed590ea1a69b4cfc4317b11a74ca76571b9a9bfb6b2295454fcae08e7607b2565b3aaa404a2baab4a4a807d04be9262717acec8035703032e989c159d754a640147f079ae90f81a37d0872a65dff3ac04ce72a710f181af81841c78579d196a20b6ac8184acb2b8936f32c9302e78707dade56f56a20632263d6b825352ba0e16c569cb65eec0578e41c4c1dab154bf387e0dfaa5635b2e17c0a3adc0700c2faa861597e8700e1ffad5e320f5fa3b9b280b2c81e86e0616488598c1f5dbefe7769ac8451714c7a02d898f57d1edb4a36dea1dc96dafe17d65bcf82a3dd99b868e47bf293ef9d5676f19d0f2b401d6f296b53c59956552f441a5e80df39698a53c4dfd83ec68f9e6aab746f596f937291396399eb1dd6d848574f66d44c0587438c5cd2ca9ec036cf37f0b0de3ebb0c8d80d9a1672b079a95dac8b45a2e2f439ee36e2e48b8db192b550550564771bc377292cdb98a735bb4ffca3a5fdf47ccec8e3b4f77ce450ca314cf8d69fe8047a3f22878e20fcdaff19f79e7434a3c746ebefac0dca7bf7dfbc36328542a6edb820b046600432719855c908c5604614532916a51dc32363fdba353d22d40c25b264e141fc88e82de6f851fa0349af1889da620490914b38808c3880440e860248c3c16513f65ae35786fd00d2ec08206309203d9c12f92a808ca6b80254c19100d29401a447c5226ea72f6500697d00197b3be92355e5d713a3238999b16dc1a2646ac606e245d6be134c3ebc8d41b32bcfd0ec6ed1e3c48a97becfd8ffff8cf51750b65c46aa38fcb211ed36e06ddc30edc657387689ea5ae68c04575f54db8239f95583c21d259e3d51a9c80984574c3ab62bd2debfb351fa2b49df5f09d88a559dc9167f25e0247f69659ca9fc9586f82b6ec05f69f5fd9506dfb13c25f8bc593c83898168ef7819edb16790fea93656c29531b92dc3e9b631e7adb35c01e3727499d6e15008d849b3385d64ef9638319907d92dcef6af04245d64f6d8be210d990cdc472248b8432a9797f8f46523e3e668992de55ca7de35d729a1aa53e9b3b8ea53ba3241e5b634cec1ad82dbf229f257908c2c9ec50b0e635956966141f1157268c47b09e0bdc470e7254625ff212e1ae2bd9832f41c702bb4fca25bfb4b4174e61acb79826461243f15364c32fc34462ea121730a88b0635c868d7c0e5c2e0918c13f3ec1ee2049d102d7fe49ea16fc85002be94fc0ae8acafc3b702f455adcf7b5f2e46906e10294915cc077a9785d5d9574627f8904bb8a21f13edb8a7ed9063b20a15ccd22152117b762a0148b24c4e5c5ad7e469696ab344d799b2b4dffd1a6fc93fef49d8fcc2e2eb7e75d6fd5cd2e2fafcecdf6da6e6df6d1f6ba5a7db8d39eebd197f575e95fecb5bbb3bdd5ee34ded7ddca6acf2daeb87317967b8bd38b2bf3ed8b8a7f0c99def9fe2e0d55ed6e77b5ebf07f5b2cae3c5a4d567cacd310ed8a33e0e9bd73b32b0036476db4baacbb0ed8bdd98797a9e111374bfd0bedae9b5b5de97567e77a8aeb00e9eb77e0786e757ef191c7f744efe581e5fcd06b5cee63cfa9f44df21f4350bb47786176e551225777f1dc6cf771b7d47edcbd7fa1bde22163d7b32b1ebe62cd9ae66bddd5deeadceab2f3ff71488969ffff18e132651a3cdac61cb22ce9dd1756da17d70806ed50684aa83eb278b13d3ffdf0e3bdf63ab05cef752fcc097569ee1f349552ff05ee7357f400d00700008101010100204b21f3cba072cc493e70861540df4677b498b0505a8b8e2a346b85a0c2dd2fc4263c4a7d8629026c4eb594ad96fac2bfe5f8ffebb9c841c353920b7b8ec11abc0100d90778da8d563b8f1c4510eedbf7e37cf209d9e60808402496c0dcdaac4e8ece01090112afe83043ef74ed4e6b677a86ee9edd5b3b2121b049888d842c84c0c1456702eb20b036424242c2e00408800c24fe03d53db3f33a58e860b6bbeaebeaeaaaafaab7f55bff9d1a796df0e5798263c37cc89f2fbe657e1eb8c7cb92e0de5f83c1eded95e4fded2d08150faf5ea5237e69f7855db2d3c199e351e5915a339c0b900d4103681849dff5c09daa3818bc34ec5057f319d54036b6c640752cc1617c024a17515d1a6b2f945c2f48a3ab3d09ca0b7dd68ab9d097078d292cd4267e9c39f089a70faea351378c85563b11c8802bf44c383eccc0cf20cd39e55a9d31df4c766ee487eed4f528174e4425baab412ab2fd44400f1dab73046827567402f6ece195a73495139455b44ee4ead4bb1db3594b2a94b929fa51367179f0f4882adc00722dea6c6edb0798d3452a7fd60d858643ed8c2598c8297bf18227220efe2f948148a1851bbb515c72a47ce34cbbeec655133b0106781de0c9aa059f8f41f3200b19833148090c41870e1c465c528b9b73c1c2798a3a57b5c2c0cfe276de28b9f0b90027552b7e6375c085d35a0691f6ac7a7768c39351b2a4eabb54b8e0dba3486d2b597131b1f0b3553ab68cff9c15a9dec3adc83b0327b5764a645b3bbd7c77b2ce294f6a755cf4a278e473d7c1692b91a74e75d083a9b5d828596cb8218364a6175132eb4b782fe61202581d2b906ec926dcee4a2cd2302de6ec9354785ea52d5bd5900bda21ea652849adab4030243b676debdc60af83126d32d91c2d34a85341c20682e6d233ab41b8f02f154e6a05e4e9b897c2b319c990c52e3a859123b533d932bbdf76c276c527c2e4b21ceb4d8cd8aa8bb1b56dac6d90260d1b8db10c036bbaa54063abace4ba8ea2241c3da3f77980ddaa92bd2e7628c7629ab617f54c2527174b05a6ae8a8236da3229af186acd0293fea689c65e7716ccb0eb61a892b5e548eeca2475a55ec7d3d32658c78357533c329d62a2b5eda28a6cb492c93f3758e35524f9ac128236578e11276e742c286468aca330a42cf661ab98b783ebbd58643cafff27cf7b71c4685a678db575669c5f1543c3e0735af70bef07a975ec4a819b769132cbcc6379f1637c36f3278f7c7debe2cb1f7c7eadd434c8feb73fdd3bfaf4956223c0f1fcb4fec587792193fd4fee3cc31edc2956278e5f1fdd7cfc59566c1fbd39fc19d8d14999a138ee42707492b171f5c0afa848c877af9e78c7cb22f570ec3f77fb789951c882be4940930cf4f0d1db6fdc5f16528fe3ddaf0eee2fb324e3d8fb1e057942cd851ffef1fb8fc5fcd920f8af3f2e66c9fcffb84b7ff865b7ce875708c9ff60d8f137aa5a1fa900d00700001001010020742877c36a520b152b1337ea1ecd37b0c98ad07289c32fec392e7eebab9f0ac71f7bc8c718cfa75317b2e15702372a9222c4616783ee7b3f0ec6358f8c328eea00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72410000d00700001001010020058e23368b919493d6ac61d27f66b829a53893e88ddde857d3b82d913960960d22fa36f397752b98c295e3b31927f740127c0a99e76f8bfeea88f44466b8fbfd00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea990000d0070000100101001f43fe868e263d8134cf705aa85e26ce78ebb058edd558865fa3d240f5cb9e50c2389e9c8276eac800b7233a552045b2e79124c97e5156a0649849cc7f5d09eee600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000d0070000100101001f29e82b08ccf15e2187f29fea11ee3f4974f41b51e45b19f353348d8848b86fb71cadd88630456b7a1c60803c7b402487d41fbf18f0b0a13b4cca1f740447938300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000d0070000100101002047a8b784c3765b5c63ac52e3d8461b80bc2d3e3f62434f8accb277d9f2487cfd3c0728fcd26b5119a11288e5db46bc5b547877e220971609d1cef8cba443340800005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974280000d007000010010100203e701fbafd4149bc95b55a6bfc3b78246f5c2668ccc05ed4059a36ceb38f140b31e3b69e15f2579571e5bde39e034947271599c200e540b3949112bef163074c00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000d0070000100101001f0cc7352e60f4f8476783d6d1b48766a111c56fee2c1a552e76a75c92bc17de172f994ffc854c09717c904054819ca7a17379ddecaf531c439b35337ba099b81300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4050000d0070000100101002040965063a83be2d53b36c8d7e0775f503c2caa1407e586314562aace52c272fe60659e196413a6c9db4168470bcabb9a5851121c10c7b665f363f6cd4d1e4bda00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000d0070000100101002074ea7468b2a031c4cd53bf10ec3ac66b0c4b5c8779e045f1ef8d9c7b116be649217ff340107d0163397b99918ee2ce822b66cd6fce7b385af97a04671136e2ee00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0000d007000010010100204dfb21ca5140582379bc026792c16b4cf97827143a4a9cd99ae70b3e6016cd6316bcbb9f1cb1233f12a0bbcd9debafa64724d0459b5c8d3cb67ceddfb2e3962500005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d670000d0070000100101002033446a3a94ade71dff3edb786259679487ab701bbc147490b1d4159fecf545fa22fee0698db16bf616465e5cebb985bfc4d9ed1ec4a55e38997dd4b4bbc427eb00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c20000d0070000100101001f3f67edd35bf731a07f40c638e8812112cd7d1baa39ec7dac4a1b2f0c83ac8bd53689b56dba69a7386e3860a6f8976695ac0bc2b5dacae91080f1d54df2dac0c000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b44767070000d0070000100101001f1e030564013603d54f9e983b63cd940f8ff09ae038b14813f4021bb0c09ebb640d90cb4f8d57be2809f492a51737b671a5f549d4efa8e7efdaeaa9663c09d1ad00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450710000d007000010010100205cea642eecf05568ce8c5564e63349eea3b816108914ba2ab5efffbb8ea467265f0b6d474f03ed02a3bf529fd6e55a595cbf8dd1adf4311cb9c51e862f8a535400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000d0070000100101001f4556076cc86e0840bf69664f1ef8fcd4d91abda313d08e7840d24ba45cb429cf12b7d3a1f64250c19d1b975e7b107853beff70ebfc4c27c44f825dc05cdc9cd600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000d0070000100101001f354d903ad0f2c6cc9d9a377d681ffaa00475d1e559e48074b4c8cce3111d5c172903b2f179ad4d736dda4e7d1b6a859baeab9dde5e5e495ce09733ec4650634400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb400000d0070000100101001f1766fa716a828da244c9ce52919b7a19acb38dbd110d1bb0039bb2477c17e4465dceecb8330ed5ee9de1330930dfcfa1a5e8149ce8536a82c0093642adf7328200005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc0000d00700001001010020488923db1c78fa430a3a9eab75f4ee467c7b9a3d3b4eb3bd08e183c82ef79b9102a4d2a7d1ec79c96b404911ae1b10f579bd82a660011c1ca2b872b30ef7dcac00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000d0070000100101002031ca6aeda725c01ed6aa6199dd2767930803051d3bc2897956bc9f97f8db5abf3bf243b775b4020f0c96d8ad197d591d11f8a51760c19fdc81134eff06a1941f00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88000001 +DMLOG APPLIED_TRANSACTION 3 793b276fb55f2f81cbdcfcaf882555ea5dde340f80c16e5dc652ffad52eea87c03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea30553a97dc6254ea785e8c6ee5994044fae975bfc8ef1916a24b476a984724cc5cf017000000000000001700000000000000010000000000ea3055170000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e8800000000000000000000793b276fb55f2f81cbdcfcaf882555ea5dde340f80c16e5dc652ffad52eea87c03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG CREATION_OP ROOT 0 +DMLOG FEATURE_OP PRE_ACTIVATE 0 a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc {"feature_digest":"a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"bc726a24928ea2d71ba294b70c5c9efc515c1542139bcf9e42f8bc174f2e72ff","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"INSTANT_FINALITY"}]} +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":56118,"consumed":9696},"cpu_usage":{"last_ordinal":1262304002,"value_ex":255807,"consumed":44101},"ram_usage":180802} +DMLOG APPLIED_TRANSACTION 3 dd3c62c2bccdf1a4ca01464e03c6deba265089df27e9ca08b3ec671f424a4e7e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055ac6be432e6c9fa887fb2ef020e979c440cb9a3f3458375d7dafa7e510aded96f18000000000000001800000000000000010000000000ea3055180000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc00000000000000000000dd3c62c2bccdf1a4ca01464e03c6deba265089df27e9ca08b3ec671f424a4e7e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":2,"value_ex":0,"consumed":0},"average_block_cpu_usage":{"last_ordinal":2,"value_ex":833334,"consumed":100},"pending_net_usage":9696,"pending_cpu_usage":44100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1049625,"virtual_cpu_limit":200200} +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":80800000,"consumed":9696},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":368326389,"consumed":44101},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} +DMLOG ACCEPTED_BLOCK 3 03000000030000000200000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100012d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b0200000000000000010000000000ea305503000000010000000000ea305502000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df719023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000001f20041c84dfa3dc10503182e60706eeae02db7fbda81f47ea43d623f3dfd84c7b5e063a2ee30ba7f62984f4e87938e34e291f4425f7180ae676c8a02083f489970000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0001023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000001f20041c84dfa3dc10503182e60706eeae02db7fbda81f47ea43d623f3dfd84c7b5e063a2ee30ba7f62984f4e87938e34e291f4425f7180ae676c8a02083f489971600d0070000fb05010100203b7de491b51d3d74624078bc2c5dc4420985f0350afb6923a5585b5621750c9f126d7cff0efeade2068c7b618fc754b2abb5bff8cdb9bd0ecb4432b72ae1ed380100a82f78daed5c7b8c5ce755ff1ef7357b67e3ebc6d94c3609f9e662d0b8a4659bb8eb2575dbbddbc476694b9cca2dfea3b0bbd99d647776bdbb9e1da70e0adead081045158a7894b6405524a4d21424545aa8cacb0d0815a94891fa20414284ff2a025511a245ad54737ee77cf7ceeccb71f09a87545b9e7be77b9cef7ce79cef3cbf71f44fe94f1bf5d03d9f1951f447e343fdf3d87be873f2879efef473830dea77fff59e7bbef7f440d3bfd197d9f57368d1bfa54767949ab11b9736d48cd9b8840f7a0b372ed11f35136cf0436fe80dfac0b80dbc2afa67f84d6306e6063201ad97a8ff9234d00880f033d54c84469e48cd68b03c8b3ea54dd0909531c1fc52d0b0ed95c70e2dae4f3fd29eed5de8b6a767e77a8b8fcdf6daf32a42d7cd6bdd76d9548e51317aeaedd5f5c5d5e9d9f5f576b7a72c9aa273ed73ebed9e4af025c3b4d595e9f9d9deecf4fae2cfb4558d9b09defcf4409f1a2aa7cead3d2e53ebddf6f90b8b40e6426f41a568ba89e04eaf75171f5b5c6e3f4ac8d519393476dbebab17ba73ede9e5c5738bbd75358c9e70f6e155c24ae17d44a6aeaeadaeb7e7f1327f61aedd5d5737a1d3a1f3e1e5d5b9a5b985d9c595e9b5d9eeecb9768ffae9756e8956e29db9475f6918efa23e77a1db6daff4a67b8be7daea00d316339982ed81b579743afff0f4238b2bf3d38be347558696da34d17361b9b778af3a88ef0707693c3db73adf56868958aed36dcfb5097257d61a2280580ef09890d1fac2ec3d6f1c57af61e4a877bdb74a6445ffcd681aa6a60b6bf3e02dda0ed993275414abb8369444511c0f0d594b9f517c8b1e31237624a07ff4371cd123d60e51efd0adb7da86ff63ab8f46725b10ea353d34145aad7434623774b17959a51baaf8d45f568fb8a6c3d9b5b5e5c7d5eb6a07b42a745a7bfdd83d47c727ee7bd39b87fe66539f0854767bbaa9b5dd3093f2d7a9078655417f5be683f4a5c81ecb752737e3f44d5a9f9cccad539d22ee1417cfe76a9c1a9c29b29e53ef1ad64e4faa62e3c4b0a9dbb45007e81ff5e90e663b4d2fe83d39aca9bdf8cdcb2a33ce1e489d4d8d4ac7b5def8415a6e29a755c64d9d66d262f59651832ba175dc6cd2f3ad0a40313352c533b4f3ffd03ada2854d3601718b7043ccf3b757258611fef0076d96d07d2ecce62649cc0127ae5968b8d4e1e38ddc96ecbb17da75c405b74f67c6e4ed034553cd1c92da19207457c3ed70f0c1b0c21ac685a71b19387d4d78c9c75da192c1c776901daf9131d02648088f62d173b2e62184ec68434c5f29bca465367881c84970c54f4d1c22c80549d0a2430a126fe9ede4b742b469a9637a28be0ed843e6191fd00d024d49de6bd366d0a5a6777d2dc74429b0dde36f5df9e6bec7a5859225a9339fce1c9dc60ae39a894d39e26292146a426345d7a93f272c2484b6b9e2e1154e1a0398c01a6a8778011febd839629d7b3d95d34d54c62415e4c31a2584ca6381a31acea26051d200bf4245168a23feb1ca6d5d2043cd2d9e1eda8f8f61f4e43950da9f42744a85e22fae9c3a08b2e5e0021137ecde82da8ded0adb2d78ef257a75be822622d65756a7949d1bae92fd774c0846b1104fa0872b354c43fcee7e5eb2cceaa08c0b2a62194695a9245a3dc961b6c411509c9112f456fcd80799088f838bb54d8415018cf5c23410b00c783082a10f50e84dded3abb44840118013088481f4a76fd881cda17441ad78fc81dfb8288bb7e440eef0b22adeb47e4ee7d4164ecfa1139ba2f884c5c3f22c7f70591cb6a174cf45e9898014c4c05e33982a10750d17ba2a2050223a0592d1118361ae9778cd51be612eb3957aa3975c4aadc4cb9a78eab14d660aa456f43fc36466f357e9ba03728426c01e32d8f870db33cdef01bc66b7ec378b62d9fc883fbd4017a0b8ae4b1fbd44dfc96d1db30bf35e8ad8e193c2eaec645d5b8b01a17f0fa0d5edf1c57b70aee99c7e5f60a97d10a97db2a5c1abc0b8cbbb9dae36baa3d1eacf69809ce8a9118e10581c42db234bd1d1264d57dea2e2107b5fd4035eece6adc1d6459c844b286602bf4adefd3fe7f92f6da533efd522076fd194daed5619535e0fa38f56e78155bff121a57aefcf1b77ee7d73ffde2d44f929380af57ae7cf6db5fc35720b9b9b9f9fca7fff04f3e72cf43c356be5efe95ef50ef43c3817cddfc230c7ef770e22c7c910f12ba05b9544fd1d3d923f6297dccb263414ecb8f8ed693d42f71e55b1f7e71ea3dbcc4339f7cf1c57ff8e047bef6f98d3ed0bfffbddfa0efef1e8e05ea3c3dc8c59e119833c76c4b409205c8de305a8f539ef639d94705e5437ffbf257805a244096e9419a6541802c1cb3ce03719decded17a94fab537bffde13e10c0fc28808402e4494c08c8c5f6fbdba4fd251e4ed2c9de385a0f531979861ee1b8392de34e1fb3137ed844273b365a0ffcb01e3da271b326c3d68ed9861fd6e8643f365ab77ed83be9118f9b5332ecd4313be98791a20538e3c73d013cc6cd451977f198cdfcb8ac931d1fad6b3fec7df4a88d9bb332ecec313be6878d75b2b78c52f891dd415f9ed190a6d7283eb3194e0bf99b27b324fdb2d131046c8ce4ab19389231e8eea0198a568f24ccc8823c7e4064cec5c507d8f58eb3db9a86d1a0a6039d62ed3cbbc37007e32c240f3f2848d65b2e98526010b5769ab010ae038f30f1b0e277b025f8f92fc012a09310635fd260540df077b6d2bce4647f5eea12572b34fae9bc53d4007b414c1f3719351cc2e45a47da98c714f14094031716fa8220d5eabc4ea926751db1ae09479bbacec3d7e6082462fb1461abca25c5157dde4507b51a2086c978c36344650a3d2378e671fa73468757a36d79743d753d30ed296b52d09ec5612f0283b22d4fd91dd44c795b25e102f218997a4c0750d45614c9842289d0ac0145dae9d3e6886dbd0245a283666f5a0cf7652e3b927edb50e84a24f9b8b911f2f6450ad6157d667654f6725c1e13781095c6095c40a756866653a3bc550e555cd032934211daf1045303a7069d09efb9ea4c8ed96760595ee05e97205a1662d29e4bb22a1c7fa6ae9359cfe89cb9c55d2f6881ee71268c99452f700b562d5b1a1523aec20199181db4bb70e1e346d870f3e0d1c79cac96feaa3511197562c7a6be91227a4a1e93f2382d8fb3c29aa3f218ab38045e819050a478bb8c2816e738036dbe496c7b2b734d58365171658c8f34c2d75d5846ebcdc8eced1c6b0d722c138e3564d24cae847bf4581304060ec559728fe871baa9f138454a891e93cda1abf069c8c125c2790976e1d4a6de7960ee4ebf6775c207e6867108142639236748b4227fcf8884fefb560ebe02cf66fa3cdbd4b229614a764ab856bb1ad78840bb706d53ced910b85613ae65c0d8d5ae81718cc54bb2c31a2ca4eaaf98418892b289d978cc2ec8db647f6dac54cd430309821d9c450e083949b2b45f31bbb673bbb9f7b9f5d2f05e4e35e586844ea48239adfc6095dd46019b2246227596a5a3900f24d5c897ec33dbed18927e2e14b3ff4db5b71e8e2b5d9c94ba38f1eb267d5d9c6c93aaa4b4fd7071f6949a44a4060a93c5252b46af76aa9f17f9a8ed38d5a72be161d1b986537d7a40386604cfb395626a99fbd91010518ab173cd9a77ad2db8572bbef6ec575ffbe030ab7ea44c3397c7d43ab6ec7d8b182e223fcef421e535c0d2a77032e9f85b56ebe8815339b682d93966a4d726348cef82e03b431009d0e9a53c06b221840833428f28fca9af13a231231a6e4174461ef38209a000d1b08f682888f2bc15993a2f324be42e6596e6cd88d6f1d0e22c4fa5fdf440fb99b23d19907119c6f957efacdd4fed792a6a1ab27f2015ce672d957a25426f3763619dfd083b3a2f3e074727ad952a33fd4598347de34ddae92d7af1ecdede06fb1ba52dfb22f46243ccbad8b2c957f040763767c99ee6ec2a0ec8cc80ffb1b6c5b5d8d59c5d456f95562cbc8a15bb8c8481bec479f2cb8a83576477103b2134297833766a03e859f16345c3e5014e2ce144f8fbe347e87338f7d17ff9cc37de40bccf5038390595c4d11069b50772d522cd826f2758303e7b993d600b7e247ed49492c8ee0436d4cac3615d2f87d4113d31a3127ecb3a651878d20f7e6058a7a20b8abb3b790492d3493b816202e9da850e1020c1715cd2e19ac0034c1412e8900b3329c7b818a4a038c326b5442e947a482ee11feb6eff967ecc4af4b0a93df57212ab2306e25629e6b054cca1e742d857cce136e90dbd62862e15511a70ca4eeda2a343d6d1c66ba3ad815acb1c45be8e75370825dac2727c717440afb364676ff3ca3de21e7a1b14e6ad2e40eca2bd1db718648f2a151f5d9be326fa1af179c04a964f23407ad373ff00fdbc66e20a9868a6e24b34d070054ab45329e15f30da6e38613b54129f42944b2cca25c1d2568a599fe40cc08a40086639cbca8bf9c04cb15c21c6dd3f90287bec23b44687a34186a6010df5a3dc6e83a6fb395d55ca871ec8e932b4f4dff50d2261b00709d51e2095b84c7b8084d0ecdfa6bf6e593346bcf1a069a6147c3bae9271dabb19d2f18e2ca7f470d0d4db7989efc2d471029d4b6e48579071e69a73cee2097b75459d7711f21379d4fbfd27096e54c49d664487980c1249ee79d2435ea9f20e12d9526d891c083a7af613b97950aaaa2e5ecadeeb7bcb8de5c949d699d0facebc0b03a983cc81613726c1eee85b728274a564f0835229d2eeb4f5cbd2495adaa14e7857b52a5bc14dd007466aba21a8e469a2b7d124d84a934068120dd224649a18a189014d42170dd0049ed95b0cb248f5bedcb868a9703bd0447291c8da1c40b3e93940be207c54a4a6b886bc7b117510e2401155977b7f1545d441506511065af8da8aa8bb2162b13bfbaa8ba8af0e9143fb8248e3fa11b9635f1071d78fc8e17d41a475fd88dcbd2f888c5d3f2247f7059189eb47e4f8be20b27b11752f4caeb188ba072aba84b05b11f5b7c52f0ff7d1fa243badcfa0a68d5cb2cdfa88ed89c5ba180a3b617822313ce4122f650f55db492aa32ac3c5b925e55d591f52c61c4103346f04d4499660a128307e701712259ca6a0686e2bb738620389fe53f74397cc27502417c677740825f24bab6b48755e104ec1521e88c7b8f1ce61d6e6e46052e81dba402e3489b3cf8fa03f5130266727d7127d87f065450042870b65e4efa896783641cea40b386e534211cd496d89d4789ce65d6a7642602ea55261d877e1a00417a5b0469efa6b46c81821b6fe0b6b62899edd12a79ce47a13416de4108f3b1855443db8d34456556e6d69dc1c433585c2a0f0a4bfcf147074c48d4027e4ea1c9132aceea269dcb2cb0ee54c30d0ed0301b22bf0edfa910ba49183f2e21b12d20588700a0d3bcc63b343a374ba98ce0a914bc8ac629a6cad8684a5810d61c3622925253cf062a7b86bcbd8d82585e3b1a0d551445308dce98108b526112af5d4ab6b75779010321fe9dd61c70f725aa32665158d143697eb10a2b01cc41c82e32d92405471e94a3e90612401c97eca45083c25b8268fb4d1d41e0ce8076632174bd2a67fa5ad2106a2649c079c11d2888b9504c57fc69b03ba4896dcfc1037be2c3b66998e24f0e18f983d667203d9e6e771760b4d8c789c4cfcd873c20fe2dfe94e19df97c5a6b314ac09050981a3ac1d5bd9ad0c0195f7337251b13375c94553fa09faf8d9f7de4e6c232e51b0fa5d4d7e93d4cd82c39c1c3a46b84cf2da25da4ffb1217d21d874a0a071c1712754422ac5c05e864ef1b958188092d5f02909091a01ecd43cf46f60724b28fd9aa7b26c6583e41264cea100a706249b344b44b6622b49296b48eeb94c50a30904f218e9b5c4f844a75c8b130982d4c948a59fa211b0a0b858d14ae8b0ae228c9ee0c4228a4b96bb72004210dc270e5d930600b1c3026c54f683635ab00d6fa688af860cb443a244c1583c0389a4a7e01d9bc3728f5641e4c4d3cf524498b2e363ad80cf5b1f9206340d0ab2081149a08de95e7fc098c40c9b084430c670cf840c2c30f80c1001c72a3194cc61aa744850e3d04b1b03d3ab8d9413ec822bd068f000b0550d7b21ea77848e6d0820405be34e44ba3c3bb979b21d294f9a6ac6c324898105f3eef85321bd08c03a944affa37399518f854a264b612a46b78e9665837e93605c7df919d97b17e9c682fbe3dbc5d7dd9d216f910179773b795c36d3596d57b7a3f85d95244a87095c41ae3ab3cbe7a2fd4522e197c1fc80d02f26553a9bb6d92b5975c9529ea3da1226175581e8e9d003afca4be5a223c8d1dd6b1ca4d86d089879b7c07a5515d1e6079e220f730fc4f674e6e99ea7c4a6fcbec5b315b97b3f59eb3ab0923db26f00ea026b3fed1701dc9cabe6d5492748924e97c0ed7882d6435fae7b86830703b4af160f1a12cd9b407799af2ae171cad3c821f620a5c698a59f511d988b0c5f7a8016e3f291dc2ab0777d1456fbf1dd503b80a996be23700e23d231d6c71ef05b7b3011d3bf7fefb062960728e82342d8b6b900cc5e50dbec311c38292e1586a4afa350f91f328e15902d5b4151ce636bcf6509cd8a85526bf902f5e62d5e00b4f7cc58ebdddca313462bd02c9e921b5ca387a6374204d9fd7261057f07f5de10d68ba6d6a8ec28b4a668ed804fecbeb540c5394c5d81d5f712a95e0a70ced28d8eedc5edb8e1a7e478d6bd851c38f7ba51d855e77e73bb7c585403f322b4766db062503831a25811a7bd801efdd8148311e194556f468346b4cab1ae221176535ef4aa65ff6d6eed590ea1a69b4cfc4317b11a74ca76571b9a9bfb6b2295454fcae08e7607b2565b3aaa404a2baab4a4a807d04be9262717acec8035703032e989c159d754a640147f079ae90f81a37d0872a65dff3ac04ce72a710f181af81841c78579d196a20b6ac8184acb2b8936f32c9302e78707dade56f56a20632263d6b825352ba0e16c569cb65eec0578e41c4c1dab154bf387e0dfaa5635b2e17c0a3adc0700c2faa861597e8700e1ffad5e320f5fa3b9b280b2c81e86e0616488598c1f5dbefe7769ac8451714c7a02d898f57d1edb4a36dea1dc96dafe17d65bcf82a3dd99b868e47bf293ef9d5676f19d0f2b401d6f296b53c59956552f441a5e80df39698a53c4dfd83ec68f9e6aab746f596f937291396399eb1dd6d848574f66d44c0587438c5cd2ca9ec036cf37f0b0de3ebb0c8d80d9a1672b079a95dac8b45a2e2f439ee36e2e48b8db192b550550564771bc377292cdb98a735bb4ffca3a5fdf47ccec8e3b4f77ce450ca314cf8d69fe8047a3f22878e20fcdaff19f79e7434a3c746ebefac0dca7bf7dfbc36328542a6edb820b046600432719855c908c5604614532916a51dc32363fdba353d22d40c25b264e141fc88e82de6f851fa0349af1889da620490914b38808c3880440e860248c3c16513f65ae35786fd00d2ec08206309203d9c12f92a808ca6b80254c19100d29401a447c5226ea72f6500697d00197b3be92355e5d713a3238999b16dc1a2646ac606e245d6be134c3ebc8d41b32bcfd0ec6ed1e3c48a97becfd8ffff8cf51750b65c46aa38fcb211ed36e06ddc30edc657387689ea5ae68c04575f54db8239f95583c21d259e3d51a9c80984574c3ab62bd2debfb351fa2b49df5f09d88a559dc9167f25e0247f69659ca9fc9586f82b6ec05f69f5fd9506dfb13c25f8bc593c83898168ef7819edb16790fea93656c29531b92dc3e9b631e7adb35c01e3727499d6e15008d849b3385d64ef9638319907d92dcef6af04245d64f6d8be210d990cdc472248b8432a9797f8f46523e3e668992de55ca7de35d729a1aa53e9b3b8ea53ba3241e5b634cec1ad82dbf229f257908c2c9ec50b0e635956966141f1157268c47b09e0bdc470e7254625ff212e1ae2bd9832f41c702bb4fca25bfb4b4174e61acb79826461243f15364c32fc34462ea121730a88b0635c868d7c0e5c2e0918c13f3ec1ee2049d102d7fe49ea16fc85002be94fc0ae8acafc3b702f455adcf7b5f2e46906e10294915cc077a9785d5d9574627f8904bb8a21f13edb8a7ed9063b20a15ccd22152117b762a0148b24c4e5c5ad7e469696ab344d799b2b4dffd1a6fc93fef49d8fcc2e2eb7e75d6fd5cd2e2fafcecdf6da6e6df6d1f6ba5a7db8d39eebd197f575e95fecb5bbb3bdd5ee34ded7ddca6acf2daeb87317967b8bd38b2bf3ed8b8a7f0c99def9fe2e0d55ed6e77b5ebf07f5b2cae3c5a4d567cacd310ed8a33e0e9bd73b32b0036476db4baacbb0ed8bdd98797a9e111374bfd0bedae9b5b5de97567e77a8aeb00e9eb77e0786e757ef191c7f744efe581e5fcd06b5cee63cfa9f44df21f4350bb47786176e551225777f1dc6cf771b7d47edcbd7fa1bde22163d7b32b1ebe62cd9ae66bddd5deeadceab2f3ff71488969ffff18e132651a3cdac61cb22ce9dd1756da17d70806ed50684aa83eb278b13d3ffdf0e3bdf63ab05cef752fcc097569ee1f349552ff05ee7357f400d00700008101010100204b21f3cba072cc493e70861540df4677b498b0505a8b8e2a346b85a0c2dd2fc4263c4a7d8629026c4eb594ad96fac2bfe5f8ffebb9c841c353920b7b8ec11abc0100d90778da8d563b8f1c4510eedbf7e37cf209d9e60808402496c0dcdaac4e8ece01090112afe83043ef74ed4e6b677a86ee9edd5b3b2121b049888d842c84c0c1456702eb20b036424242c2e00408800c24fe03d53db3f33a58e860b6bbeaebeaeaaaafaab7f55bff9d1a796df0e5798263c37cc89f2fbe657e1eb8c7cb92e0de5f83c1eded95e4fded2d08150faf5ea5237e69f7855db2d3c199e351e5915a339c0b900d4103681849dff5c09daa3818bc34ec5057f319d54036b6c640752cc1617c024a17515d1a6b2f945c2f48a3ab3d09ca0b7dd68ab9d097078d292cd4267e9c39f089a70faea351378c85563b11c8802bf44c383eccc0cf20cd39e55a9d31df4c766ee487eed4f528174e4425baab412ab2fd44400f1dab73046827567402f6ece195a73495139455b44ee4ead4bb1db3594b2a94b929fa51367179f0f4882adc00722dea6c6edb0798d3452a7fd60d858643ed8c2598c8297bf18227220efe2f948148a1851bbb515c72a47ce34cbbeec655133b0106781de0c9aa059f8f41f3200b19833148090c41870e1c465c528b9b73c1c2798a3a57b5c2c0cfe276de28b9f0b90027552b7e6375c085d35a0691f6ac7a7768c39351b2a4eabb54b8e0dba3486d2b597131b1f0b3553ab68cff9c15a9dec3adc83b0327b5764a645b3bbd7c77b2ce294f6a755cf4a278e473d7c1692b91a74e75d083a9b5d828596cb8218364a6175132eb4b782fe61202581d2b906ec926dcee4a2cd2302de6ec9354785ea52d5bd5900bda21ea652849adab4030243b676debdc60af83126d32d91c2d34a85341c20682e6d233ab41b8f02f154e6a05e4e9b897c2b319c990c52e3a859123b533d932bbdf76c276c527c2e4b21ceb4d8cd8aa8bb1b56dac6d90260d1b8db10c036bbaa54063abace4ba8ea2241c3da3f77980ddaa92bd2e7628c7629ab617f54c2527174b05a6ae8a8236da3229af186acd0293fea689c65e7716ccb0eb61a892b5e548eeca2475a55ec7d3d32658c78357533c329d62a2b5eda28a6cb492c93f3758e35524f9ac128236578e11276e742c286468aca330a42cf661ab98b783ebbd58643cafff27cf7b71c4685a678db575669c5f1543c3e0735af70bef07a975ec4a819b769132cbcc6379f1637c36f3278f7c7debe2cb1f7c7eadd434c8feb73fdd3bfaf4956223c0f1fcb4fec587792193fd4fee3cc31edc2956278e5f1fdd7cfc59566c1fbd39fc19d8d14999a138ee42707492b171f5c0afa848c877af9e78c7cb22f570ec3f77fb789951c882be4940930cf4f0d1db6fdc5f16528fe3ddaf0eee2fb324e3d8fb1e057942cd851ffef1fb8fc5fcd920f8af3f2e66c9fcffb84b7ff865b7ce875708c9ff60d8f137aa5a1fa900d00700001001010020742877c36a520b152b1337ea1ecd37b0c98ad07289c32fec392e7eebab9f0ac71f7bc8c718cfa75317b2e15702372a9222c4616783ee7b3f0ec6358f8c328eea00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72410000d00700001001010020058e23368b919493d6ac61d27f66b829a53893e88ddde857d3b82d913960960d22fa36f397752b98c295e3b31927f740127c0a99e76f8bfeea88f44466b8fbfd00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea990000d0070000100101001f43fe868e263d8134cf705aa85e26ce78ebb058edd558865fa3d240f5cb9e50c2389e9c8276eac800b7233a552045b2e79124c97e5156a0649849cc7f5d09eee600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000d0070000100101001f29e82b08ccf15e2187f29fea11ee3f4974f41b51e45b19f353348d8848b86fb71cadd88630456b7a1c60803c7b402487d41fbf18f0b0a13b4cca1f740447938300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000d0070000100101002047a8b784c3765b5c63ac52e3d8461b80bc2d3e3f62434f8accb277d9f2487cfd3c0728fcd26b5119a11288e5db46bc5b547877e220971609d1cef8cba443340800005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974280000d007000010010100203e701fbafd4149bc95b55a6bfc3b78246f5c2668ccc05ed4059a36ceb38f140b31e3b69e15f2579571e5bde39e034947271599c200e540b3949112bef163074c00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000d0070000100101001f0cc7352e60f4f8476783d6d1b48766a111c56fee2c1a552e76a75c92bc17de172f994ffc854c09717c904054819ca7a17379ddecaf531c439b35337ba099b81300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4050000d0070000100101002040965063a83be2d53b36c8d7e0775f503c2caa1407e586314562aace52c272fe60659e196413a6c9db4168470bcabb9a5851121c10c7b665f363f6cd4d1e4bda00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000d0070000100101002074ea7468b2a031c4cd53bf10ec3ac66b0c4b5c8779e045f1ef8d9c7b116be649217ff340107d0163397b99918ee2ce822b66cd6fce7b385af97a04671136e2ee00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0000d007000010010100204dfb21ca5140582379bc026792c16b4cf97827143a4a9cd99ae70b3e6016cd6316bcbb9f1cb1233f12a0bbcd9debafa64724d0459b5c8d3cb67ceddfb2e3962500005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d670000d0070000100101002033446a3a94ade71dff3edb786259679487ab701bbc147490b1d4159fecf545fa22fee0698db16bf616465e5cebb985bfc4d9ed1ec4a55e38997dd4b4bbc427eb00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c20000d0070000100101001f3f67edd35bf731a07f40c638e8812112cd7d1baa39ec7dac4a1b2f0c83ac8bd53689b56dba69a7386e3860a6f8976695ac0bc2b5dacae91080f1d54df2dac0c000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b44767070000d0070000100101001f1e030564013603d54f9e983b63cd940f8ff09ae038b14813f4021bb0c09ebb640d90cb4f8d57be2809f492a51737b671a5f549d4efa8e7efdaeaa9663c09d1ad00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450710000d007000010010100205cea642eecf05568ce8c5564e63349eea3b816108914ba2ab5efffbb8ea467265f0b6d474f03ed02a3bf529fd6e55a595cbf8dd1adf4311cb9c51e862f8a535400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000d0070000100101001f4556076cc86e0840bf69664f1ef8fcd4d91abda313d08e7840d24ba45cb429cf12b7d3a1f64250c19d1b975e7b107853beff70ebfc4c27c44f825dc05cdc9cd600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000d0070000100101001f354d903ad0f2c6cc9d9a377d681ffaa00475d1e559e48074b4c8cce3111d5c172903b2f179ad4d736dda4e7d1b6a859baeab9dde5e5e495ce09733ec4650634400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb400000d0070000100101001f1766fa716a828da244c9ce52919b7a19acb38dbd110d1bb0039bb2477c17e4465dceecb8330ed5ee9de1330930dfcfa1a5e8149ce8536a82c0093642adf7328200005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc0000d00700001001010020488923db1c78fa430a3a9eab75f4ee467c7b9a3d3b4eb3bd08e183c82ef79b9102a4d2a7d1ec79c96b404911ae1b10f579bd82a660011c1ca2b872b30ef7dcac00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000d0070000100101002031ca6aeda725c01ed6aa6199dd2767930803051d3bc2897956bc9f97f8db5abf3bf243b775b4020f0c96d8ad197d591d11f8a51760c19fdc81134eff06a1941f00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e880000d0070000100101001f03670020103e7843695b5c83b87d3183f9c0b21ee28f46ce80c061311835f436600f684f91df8e1e4a21233f1f97505a789189b4272a0d8bc2666891f93298e000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc000001 DMLOG START_BLOCK 4 DMLOG FEATURE_OP ACTIVATE 1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241 {"feature_digest":"1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"f3c3d91c4603cde2397268bfed4e662465293aab10cd9416db0d442b8cec2949","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"ONLY_LINK_TO_EXISTING_PERMISSION"}]} DMLOG FEATURE_OP ACTIVATE ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99 {"feature_digest":"ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"9908b3f8413c8474ab2a6be149d3f4f6d0421d37886033f27d4759c47a26d944","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"REPLACE_DEFERRED"}]} @@ -146,40 +150,41 @@ DMLOG FEATURE_OP ACTIVATE d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d9 DMLOG FEATURE_OP ACTIVATE 6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc {"feature_digest":"6bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"68d6405cb8df3de95bd834ebb408196578500a9f818ff62ccc68f60b932f7d82","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"CRYPTO_PRIMITIVES"}]} DMLOG FEATURE_OP ACTIVATE 35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b {"feature_digest":"35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"e5d7992006e628a38c5e6c28dd55ff5e57ea682079bf41fef9b3cced0f46b491","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"GET_BLOCK_NUM"}]} DMLOG FEATURE_OP ACTIVATE 98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88 {"feature_digest":"98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"01969c44de35999b924095ae7f50081a7f274409fdbccb9fc54fa7836c76089c","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"BLS_PRIMITIVES"}]} +DMLOG FEATURE_OP ACTIVATE a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc {"feature_digest":"a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"bc726a24928ea2d71ba294b70c5c9efc515c1542139bcf9e42f8bc174f2e72ff","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"INSTANT_FINALITY"}]} DMLOG CREATION_OP ROOT 0 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":55376,"consumed":1},"cpu_usage":{"last_ordinal":1262304003,"value_ex":244809,"consumed":101},"ram_usage":180802} -DMLOG TRX_OP CREATE onblock e11ba456c63db33e0320a8f51418e4e0af5ee0d38fd7d6cf13a089eda823f8f3 0000000000000000000000000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed323274023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e841639eb3a733e9536932b85f63002945d82e25a0ef948f220ba098df51ab2f5d9d5fc55180118b2a44ae7b7ad158b7de8fee6df8ac1c5afd3681c5b11460ac96000000000000000000 -DMLOG APPLIED_TRANSACTION 4 e11ba456c63db33e0320a8f51418e4e0af5ee0d38fd7d6cf13a089eda823f8f304000000033b3d4b010000000446ce40fcba331770d4e40c1a69d054d3a9a5ed89ef08b50cc808e32501006400000000000000000000000000000000000000000001010000010000000000ea305518ea4ce1eae6e5bb75076db4c0bc4ba7f64bac448aa056072cc35f5c5e62230218000000000000001800000000000000010000000000ea3055180000000000000001010000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed323274023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e841639eb3a733e9536932b85f63002945d82e25a0ef948f220ba098df51ab2f5d9d5fc55180118b2a44ae7b7ad158b7de8fee6df8ac1c5afd3681c5b11460ac9600000000000000000000000000000000e11ba456c63db33e0320a8f51418e4e0af5ee0d38fd7d6cf13a089eda823f8f304000000033b3d4b010000000446ce40fcba331770d4e40c1a69d054d3a9a5ed89ef08b50cc808e3250000000000000000 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":56117,"consumed":1},"cpu_usage":{"last_ordinal":1262304003,"value_ex":256384,"consumed":101},"ram_usage":180802} +DMLOG TRX_OP CREATE onblock 4d5e4d90e4202f63d5763bb7dca7fcd081b155306a82f20a9acce09df0e5c2d8 0000000000000000000000000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed323274023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000000000 +DMLOG APPLIED_TRANSACTION 4 4d5e4d90e4202f63d5763bb7dca7fcd081b155306a82f20a9acce09df0e5c2d804000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e501006400000000000000000000000000000000000000000001010000010000000000ea30551f4b48aa5b23f57381aca9e958853d170378813437993dbb6599a35510d8c8d119000000000000001900000000000000010000000000ea3055190000000000000001010000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed323274023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000000000000000000000004d5e4d90e4202f63d5763bb7dca7fcd081b155306a82f20a9acce09df0e5c2d804000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e50000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG RAM_OP 0 eosio code update setcode eosio 199492 18690 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":95191,"consumed":6881},"cpu_usage":{"last_ordinal":1262304003,"value_ex":256384,"consumed":2101},"ram_usage":199492} -DMLOG APPLIED_TRANSACTION 4 3d5251a1c9a3cd8d7baad33a381b9e09858e0503df1751181fd60202251c23fb04000000033b3d4b010000000446ce40fcba331770d4e40c1a69d054d3a9a5ed89ef08b50cc808e3250100d0070000dc060000000000000000e01a0000000000000001010000010000000000ea3055378d583c2888f3564b4db37bfb52d74d038e54fcc63aeb57cf27b03c001e97a519000000000000001900000000000000010000000000ea3055190000000000000002010000000000ea30550000000000ea305500000040258ab2c2010000000000ea305500000000a8ed3232cb99010000000000ea30550000be99010061736d010000000198011960000060027f7f0060037f7f7f0060047e7e7e7e017f6000017e60047f7e7e7f0060057f7f7f7f7f017f60037f7f7f017f60027f7f017f60027f7f017e60057f7f7f7f7f0060067e7e7e7e7f7f017f60017e0060027e7f0060047e7e7e7e0060037e7f7f017e60017f0060017f017f6000017f60027f7e0060047f7e7f7f0060037e7e7e0060037f7e7f0060047f7f7f7f0060027e7e0002f0052403656e760b64625f66696e645f693634000303656e760c656f73696f5f617373657274000103656e761063757272656e745f7265636569766572000403656e760561626f7274000003656e760d6173736572745f736861323536000203656e760b6173736572745f73686131000203656e760d6173736572745f736861353132000203656e76106173736572745f726970656d64313630000203656e7606736861323536000203656e76095f5f6173686c746933000503656e760473686131000203656e7606736861353132000203656e7609726970656d64313630000203656e760b7265636f7665725f6b6579000603656e76207365745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000103656e76066d656d637079000703656e76206765745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000803656e76167365745f70726f706f7365645f70726f647563657273000903656e760c63757272656e745f74696d65000403656e76146765745f6163746976655f70726f647563657273000803656e76087072696e74735f6c000103656e76126173736572745f7265636f7665725f6b6579000a03656e760c64625f73746f72655f693634000b03656e760c726571756972655f61757468000c03656e760e7365745f70726976696c65676564000d03656e76137365745f7265736f757263655f6c696d697473000e03656e76197365745f70726f706f7365645f70726f6475636572735f6578000f03656e761370726561637469766174655f66656174757265001003656e76067072696e7473001003656e761469735f666561747572655f616374697661746564001103656e7610616374696f6e5f646174615f73697a65001203656e7610726561645f616374696f6e5f64617461000803656e7611656f73696f5f6173736572745f636f6465001303656e760a64625f6765745f693634000703656e760d64625f7570646174655f693634001403656e76087072696e7468657800010346450015111000111010100c100802101608020817010110011818181818181808011818181818080101180818181808000808010101080101010801010102080108020202020804050170010d0d05030100010616037f014180c0000b7f0041e2c5000b7f0041e2c5000b070901056170706c7900250912010041010b0c555657595a5b5d5e5f6465660aab8b0145040010280bdd03002000102d102420002001510440428080f9d4a98499dc9a7f200251044020002001103b05428080add68d959ba955200251044020002001103c05428080add68d95abd1ca00200251044020002001103d0542808080e8b2edc0d38b7f200251044020002001103e05428080add68db8baf154200251044020002001103f054280f8a6d4d2a8a1d3c1002002510440200020011040054280808080d4c4a2d942200251044020002001104105428080808080f798d9422002510440200020011044054280808080aefadeeaa47f2002510440200020011045054280808080b6f7d6d942200251044020002001104605428080b8f6a4979ad94220025104402000200110470542808080c093fad6d9422002510440200020011048054280808096cdebd4d942200251044020002001104c054280808080daac9bd6ba7f200251044020002001104e0542808080d0b2b3bb9932200251044020002001104f054290a9d9d9dd8c99d6ba7f2002510440200020011050052000428080808080c0ba98d500520440410042808080d9d3b3ed82ef0010200b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b05428080808080c0ba98d50020015104404280808080aefadeeaa47f2002510440410042818080d9d3b3ed82ef0010200b0b0b410010310b7201037f024020000d0041000f0b4100410028028c40200041107622016a220236028c404100410028028440220320006a410f6a4170712200360284400240200241107420004b0d004100200241016a36028c40200141016a21010b024020014000417f470d0041004190c00010010b20030b02000b3601017f230041106b2200410036020c4100200028020c280200410f6a417071220036028040410020003602844041003f0036028c400b3301027f2000410120001b2101024003402001102622000d01410021004100280284412202450d0120021100000c000b0b20000b0600200010270b05001003000b05001003000b0a0041002000370388410b4e01017f230041e0006b220124002001200141d8006a3602082001200141106a3602042001200141106a36020020012000102f1a200141106a200128020420012802006b100e200141e0006a24000ba20801027f02402000280208200028020422026b41074a0d0041004190c1001001200028020421020b200220014108100f1a2000200028020441086a2202360204200141086a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001410c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141106a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141146a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141186a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001411c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141206a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141246a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141286a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001412c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141306a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141346a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141386a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001413c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141c0006a21030240200028020820026b41014a0d0041004190c1001001200028020421020b200220034102100f1a2000200028020441026a2202360204200141c2006a21010240200028020820026b41014a0d0041004190c1001001200028020421020b200220014102100f1a2000200028020441026a36020420000bfa0103017f027e017f230041306b2203240020012002200341106a1008420021044110210141002102420021050340200341106a20026a21060240024020014102490d002005420886200420063100008422044238888421052001417f6a2101200442088621040c010b024020014101460d00410041a9c00010010b200020053703082000200420063100008437030041102101200041106a210042002104420021050b200241016a22024120470d000b024020014110460d00024020014102490d00200320042005200141037441786a1009200341086a2903002105200329030021040b20002004370300200020053703080b200341306a24000b02000b970503017f017e047f230041f0006b22032400200341206a4100360200200342003703182003427f37031020032000290300220437030820032004370300024002402004200442808080809aecb4ee312001100022004100480d00024020032000103322002802302003460d00410041c0c20010010b2003200236023020032000200341306a10340c010b024020041002510d004100418ac30010010b41c000102922004200370310200041286a22054200370300200041206a22064200370300200041186a220742003703002000200336023020002001370300200341306a20022802002208200228020420086b10302005200341306a41186a2903003703002006200341306a41106a29030037030020072003290338370300200020032903303703102003200341306a41286a3602682003200341306a360260200341306a20004108100f1a2003200341306a410872360264200341e0006a200041106a10351a2000200329030842808080809aecb4ee31200120002903002204200341306a412810162205360234024020042003290310540d002003427e200442017c2004427d561b3703100b200320003602602003200029030022043703302003200536022c02400240200328021c220220032802204f0d00200220053602102002200437030820034100360260200220003602002003200241186a36021c0c010b200341186a200341e0006a200341306a2003412c6a10360b20032802602100200341003602602000450d002000102a0b024020032802182205450d0002400240200328021c22002005470d00200521000c010b0340200041686a220028020021022000410036020002402002450d002002102a0b20052000470d000b200328021821000b2003200536021c2000102a0b200341f0006a24000b840603097f027e017f230041e0006b220221032002240002400240200028021822042000411c6a2802002205460d0002400340200541786a2802002001460d012004200541686a2205470d000c020b0b20042005460d00200541686a28020021060c010b024002400240024020014100410010212205417f4a0d00410041f3c20010010c010b2005418104490d010b200510262107410121080c010b20022005410f6a4170716b22072400410021080b20012007200510211a41c0001029220642003703102006420037030020062000360230200641186a4200370300200641206a4200370300200641286a42003703000240200541074b0d00410041d9c40010010b200620074108100f1a200741086a21040240200541786a411f4b0d00410041d9c40010010b200041186a2109200641106a210a200341c0006a20044120100f1a4200210b41102105200341206a2102410021044200210c0340200341c0006a20046a210d0240024020054102490d00200c420886200b200d31000084220b42388884210c2005417f6a2105200b420886210b0c010b024020054101460d00410041b6c50010010b2002200c3703082002200b200d3100008437030041102105200241106a21024200210b4200210c0b200441016a22044120470d000b024020054110460d00024020054102490d00200341086a200b200c200541037441786a1009200341106a290300210c2003290308210b0b2002200b3703002002200c3703080b200a2003290320370300200a41086a2003290328370300200a41186a200341206a41186a290300370300200a41106a200341206a41106a290300370300200620013602342003200636022020032006290300220b3703402003200136021c02400240200028021c2205200041206a2802004f0d00200520013602102005200b37030820034100360220200520063602002000200541186a36021c0c010b2009200341206a200341c0006a2003411c6a10360b02402008450d00200710270b20032802202105200341003602202005450d002005102a0b200341e0006a240020060b980203027f017e017f230041206b2203210420032400024020012802302000460d00410041bdc30010010b024010022000290300510d00410041ebc30010010b200129030021052004200228020022022802002206200228020420066b1030200141286a200441186a290300370300200141206a200441106a290300370300200141186a200429030837030020012004290300370310200141106a2102024020052001290300510d004100419ec40010010b200341506a220324002004200341286a36020820042003360200200320014108100f1a2004200341086a3602042004200210351a20012802344200200341281022024020052000290310540d002000427e200542017c2005427d561b3703100b200441206a24000bd20303017f027e017f230041206b220224002002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722054108763a0016200220054110763a0015200220054118763a001420022004a722053a0007200220054108763a0006200220054110763a0005200220054118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c001002402000280208200028020422016b411f4a0d0041004188c2001001200028020421010b200120024120100f1a2000200028020441206a360204200241206a240020000b9a0301057f0240024002402000280204200028020022046b41186d220541016a220641abd5aad5004f0d0041aad5aad500210702400240200028020820046b41186d220441d4aad52a4b0d0020062004410174220720072006491b22070d0041002107410021040c010b200741186c102921040b20012802002106200141003602002004200541186c22086a2201200328020036021020012002290300370308200120063602002004200741186c6a2105200141186a21062000280204220220002802002207460d01200420086a41686a21010340200241686a220428020021032004410036020020012003360200200141086a200241706a2202290300370300200141106a200241086a280200360200200141686a21012004210220072004470d000b200141186a210120002802042107200028020021040c020b2000102c000b200721040b200020053602082000200636020420002001360200024020072004460d000340200741686a220728020021012007410036020002402001450d002001102a0b20042007470d000b0b02402004450d002004102a0b0bd00203047f017e017f230041106b220224004100210320004100360208200042003702002002410036020020012802042204200128020022056b410575ad21060340200341016a2103200642078822064200520d000b2002200336020002400240024020052004460d0003402002200341086a3602002003410c6a2103200541186a2802002207ad21060340200341016a2103200642078822064200520d000b20022003417c6a3602002007417f460d022002200336020020022005410c6a10511a20022802002103200541206a22052004470d000b20002802002105200028020421070c020b41002105410021070c010b1052000b024002402003200720056b22074d0d002000200320076b1043200028020021050c010b200320074f0d002000200520036a3602040b2002200536020420022005360200200220002802043602082002200110531a200241106a24000baf0302017f027e230041206b22022400200029030010172002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722004108763a0016200220004110763a0015200220004118763a001420022004a722003a0007200220004108763a0006200220004110763a0005200220004118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c00102002101b41bdc100101c2001103941bbc100101c200241206a24000b9c0303017f027e017f230041206b220124002001200041186a29030022023c00172001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c0000200120024220883c001320012002a722044108763a0016200120044110763a0015200120044118763a001420012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a0004200120002903002203423886200342288642808080808080c0ff0083842003421886428080808080e03f8320034208864280808080f01f838484200342088842808080f80f832003421888428080fc07838420034228884280fe03832003423888848484370308200120002903102203423886200342288642808080808080c0ff0083842003421886428080808080e03f8320034208864280808080f01f838484200342088842808080f80f832003421888428080fc07838420034228884280fe03832003423888848484370318200120024230883c0011200120024228883c0012200120024238883c0010200141201023200141206a24000ba70303017f027e017f230041206b220224002002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722054108763a0016200220054110763a0015200220054118763a001420022004a722053a0007200220054108763a0006200220054110763a0005200220054118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c001002402002101d0d00410041d8c10010010b200241206a24000bb90101047f230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a20034200370300200241086a2102024020044178714108470d00410041d9c40010010b200320024108100f1a200341106a24000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000bc90201047f230041306b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360224200320023602202003200220046a2205360228200342003703180240200441074b0d00410041d9c400100120032802282105200328022421020b200341186a20024108100f1a2003200241086a2202360224024020052002470d00410041d9c400100120032802282105200328022421020b200341176a20024101100f1a2003200241016a2202360224024020052002470d00410041d9c4001001200328022421020b200341166a20024101100f1a2003200241016a3602242003410036021020034200370308200341206a200341086a10421a024020032802082202450d002003200236020c2002102a0b200341306a24000bff0103017f017e047f2000280204210242002103410021040340024020022000280208490d0041004183c5001001200028020421020b20022d000021052000200241016a22063602042003200541ff0071200441ff0171220274ad842103200241076a2104200621022005418001710d000b0240024020012802042205200128020022026b22072003a722044f0d002001200420076b10432000280204210620012802042105200128020021020c010b200720044d0d002001200220046a22053602040b0240200028020820066b200520026b22054f0d00410041d9c4001001200028020421060b200220062005100f1a2000200028020420056a36020420000b980201057f02400240024020002802082202200028020422036b2001490d000340200341003a00002000200028020441016a22033602042001417f6a22010d000c020b0b2003200028020022046b220520016a2206417f4c0d0141ffffffff07210302400240200220046b220241feffffff034b0d0020062002410174220320032006491b22030d0041002103410021020c010b2003102921020b200220036a2106200220056a220421030340200341003a0000200341016a21032001417f6a22010d000b20042000280204200028020022016b22026b2104024020024101480d00200420012002100f1a200028020021010b2000200636020820002003360204200020043602002001450d002001102a0b0f0b2000102c000bb20202037f017e23004180016b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360254200320023602502003200220046a360258200342003703480240200441074b0d00410041d9c4001001200328025421020b200341c8006a20024108100f1a2003200241086a3602542003410036024020034200370338200341d0006a200341386a10421a200341086a41086a200341d0006a41086a2802002202360200200341306a2002360200200320032903502205370308200320013703202003200037031820032005370328200341186a2003290348200341386a1032024020032802382202450d002003200236023c2002102a0b20034180016a24000b4c01037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b410041d5c0001001200324000bcf0102047f017e230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a200241086a2102024020044108470d00410041d9c40010010b200341076a20024101100f1a2003290308210620032d0007210420001017200620044100471018200341106a24000baa0202047f047e230041206b2202210320022400024002400240101e22040d002003420037031841002102200341186a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370318200341186a2105200441074b0d010b410041d9c40010010b200520024108100f1a200241086a21050240200441787122044108470d00410041d9c40010010b200341106a20054108100f1a200241106a2105024020044110470d00410041d9c40010010b200341086a20054108100f1a200241186a2102024020044118470d00410041d9c40010010b200320024108100f1a200329030021062003290308210720032903102108200329031821092000101720092008200720061019200341206a24000ba103010b7f230041306b2202210320022400410021040240101e2205450d00024002402005418004490d002005102621040c010b20022005410f6a4170716b220424000b20042005101f1a0b20032004360214200320043602102003200420056a3602182003410036020820034200370300200341106a200310491a20001017200341206a20031037420120032802202204200328022420046b101a1a024020032802202204450d00200320043602242004102a0b024020032802002206450d0002400240200328020422072006470d00200621040c010b03402007220441606a21070240200441786a2208280200417f460d002004416c6a2209280200220a450d00200a21050240200441706a220b2802002204200a460d000340200441486a21050240200441786a2202280200220c417f460d00200341206a200441486a200c4102744188c5006a2802001101000b2002417f36020020052104200a2005470d000b200928020021050b200b200a3602002005102a0b2008417f36020020072006470d000b200328020021040b200320063602042004102a0b200341306a24000bcc0303027f017e097f230041206b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22033602042004200641ff0071200541ff0171220574ad842104200541076a2105200321032006418001710d000b0240024020012802042207200128020022056b41057522062004a722034f0d002001200320066b104a200128020421070c010b200620034d0d000240200520034105746a22082007460d0003402007220341606a21070240200341786a2209280200417f460d002003416c6a220a280200220b450d00200b21060240200341706a220c2802002203200b460d000340200341486a21060240200341786a2205280200220d417f460d00200241186a200341486a200d4102744188c5006a2802001101000b2005417f36020020062103200b2006470d000b200a28020021060b200c200b3602002006102a0b2009417f36020020072008470d000b0b20012008360204200821070b0240200128020022032007460d00034020022000360208200220033602102002200341086a360214200241106a200241086a104b200341206a22032007470d000b0b200241206a240020000b9f06030a7f017e037f230041106b220224000240024020002802082203200028020422046b4105752001490d000340200441186a2203420037030020044200370300200441106a4200370300200441086a4200370300200341003602002000200028020441206a22043602042001417f6a22010d000c020b0b02400240024002402004200028020022056b410575220620016a220741808080c0004f0d0041ffffff3f210402400240200320056b220341057541feffff1f4b0d00024020072003410475220420042007491b22040d0041002104410021030c020b200441808080c0004f0d030b2004410574102921030b200320044105746a2108200320064105746a22092104034020044200370300200441186a4200370300200441106a4200370300200441086a4200370300200441206a21042001417f6a22010d000b2000280204220a20002802002206460d022006200a6b210b410021050340200920056a220141786a2206417f360200200a20056a220341606a290300210c200141686a220741003a0000200141606a200c3703000240200341786a280200220d417f460d00200141706a220e42003702002001416c6a220f4100360200200e200341706a280200360200200f2003416c6a220e280200360200200141746a200341746a22012802003602002007200341686a2802003602002006200d36020020014100360200200e42003702000b200b200541606a2205470d000b200920056a2109200028020421062000280200210d0c030b2000102c000b1003000b2006210d0b20002008360208200020043602042000200936020002402006200d460d0003402006220441606a21060240200441786a2207280200417f460d002004416c6a220e2802002200450d00200021010240200441706a220f28020022042000460d000340200441486a21010240200441786a22032802002205417f460d00200241086a200441486a20054102744188c5006a2802001101000b2003417f3602002001210420002001470d000b200e28020021010b200f20003602002001102a0b2007417f3602002006200d470d000b0b200d450d00200d102a0b200241106a24000bca0102037f017e20002802002102024020012802002203280208200328020422046b41074b0d00410041d9c4001001200328020421040b200220044108100f1a2003200328020441086a3602042000280204210220012802002201280204210342002105410021040340024020032001280208490d0041004183c5001001200128020421030b20032d000021002001200341016a22033602042005200041ff0071200441ff0171220474ad842105200441076a2104200321032000418001710d000b200120022005a710600b890101037f230041e0006b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360254200320023602502003200220046a360258200341d0006a200341086a104d1a20001017200341086a102e200341e0006a24000ba20801027f02402000280208200028020422026b41074b0d00410041d9c4001001200028020421020b200120024108100f1a2000200028020441086a2202360204200141086a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001410c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141106a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141146a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141186a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001411c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141206a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141246a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141286a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001412c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141306a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141346a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141386a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001413c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141c0006a21030240200028020820026b41014b0d00410041d9c4001001200028020421020b200320024102100f1a2000200028020441026a2202360204200141c2006a21010240200028020820026b41014b0d00410041d9c4001001200028020421020b200120024102100f1a2000200028020441026a36020420000b940101047f230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a20032903081017200341106a24000b8c0405047f017e037f017e017f230041f0006b220221032002240002400240101e22040d00410021050c010b024002402004418004490d002004102621050c010b20022004410f6a4170716b220524000b20052004101f1a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d00410041d9c40010010b200520046a2107200341d0006a20054120100f1a200541206a2108200341306a2109410021044200210a0340200341d0006a20046a210b0240024020024102490d00200a4208862006200b31000084220642388884210a2002417f6a2102200642088621060c010b024020024101460d00410041b6c50010010b2009200a37030820092006200b3100008437030041102102200941106a2109420021064200210a0b200441016a22044120470d000b024020024110460d00024020024102490d0020032006200a200241037441786a1009200341086a290300210a200329030021060b200920063703002009200a3703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a2903003703002003200329033837031820032003290330370310200341d0006a41186a2007360200200341e4006a2008360200200320053602602003200137035820032000370350200341d0006a200341106a1038200341f0006a24000bc80303047f027e017f230041f0006b220221032002240002400240101e22040d00410021050c010b024002402004418004490d002004102621050c010b20022004410f6a4170716b220524000b20052004101f1a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d00410041d9c40010010b200341d0006a20054120100f1a200341306a210541002104420021070340200341d0006a20046a21080240024020024102490d002007420886200620083100008422064238888421072002417f6a2102200642088621060c010b024020024101460d00410041b6c50010010b200520073703082005200620083100008437030041102102200541106a210542002106420021070b200441016a22044120470d000b024020024110460d00024020024102490d00200320062007200241037441786a1009200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a29030037030020032003290338370318200320032903303703102002200341106a103a200341f0006a24000bd50103037f017e017f230041106b2202240020012802042203200128020022046b41386dad2105200028020021010340200141016a2101200542078822054200520d000b200020013602000240024020042003460d00034020042802302206ad21050340200141016a2101200542078822054200520d000b20002001360200200220003602002006417f460d0220022002360208200241086a2004200641027441fcc1006a2802001101002000200028020041026a2201360200200441386a22042003470d000b0b200241106a240020000f0b1052000b05001003000bfe0103017f017e037f230041106b22022400200128020420012802006b410575ad21032000280204210403402003a721052002200342078822034200522206410774200541ff0071723a000f0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410f6a4101100f1a2000200028020441016a220436020420060d000b02402001280200220520012802042206460d0003400240200028020820046b41074a0d0041004188c2001001200028020421040b200420054108100f1a2000200028020441086a3602042000200541086a10541a200541206a22052006460d01200028020421040c000b0b200241106a240020000bdd0103027f017e027f230041106b22022400200028020421032001350210210403402004a721052002200442078822044200522206410774200541ff0071723a000f0240200028020820036b41004a0d0041004188c2001001200028020421030b20032002410f6a4101100f1a2000200028020441016a220336020420060d000b02402001280210417f460d00200141046a21050240200028020820036b41034a0d0041004188c2001001200028020421030b200320014104100f1a2000200028020441046a3602042000200510581a200241106a240020000f0b1052000b170020002802002802002200200028020041216a3602000b170020002802002802002200200028020041216a3602000b7602017f017e20002802002802002202200228020041226a2200360200200141286a350200420020012d00244101711b21030340200041016a2100200342078822034200520d000b200220003602000240200128022820012d0024220141017620014101711b2201450d002002200120006a3602000b0b990303017f017e047f230041106b22022400200128020420012802006b41386dad21032000280204210403402003a721052002200342078822034200522206410774200541ff0071723a000f0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410f6a4101100f1a2000200028020441016a220436020420060d000b024002402001280200220720012802042201460d0003402007350230210303402003a721052002200342078822034200522206410774200541ff0071723a000e0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410e6a4101100f1a2000200028020441016a220436020420060d000b2002200036020020072802302204417f460d0220022002360208200241086a2007200441027441b4c2006a280200110100200741346a210502402000280208200028020422046b41014a0d0041004188c2001001200028020421040b200420054102100f1a2000200028020441026a2204360204200741386a22072001470d000b0b200241106a240020000f0b1052000b6401037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b0b6401037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b0baa0101037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b200141216a21030240200028020820026b41004a0d0041004188c2001001200028020421020b200220034101100f1a2000200028020441016a3602042000200141246a105c1a0bfd0103027f017e027f230041106b22022400200128020420012d0000220341017620034101711bad21042000280204210303402004a721052002200442078822044200522206410774200541ff0071723a000f0240200028020820036b41004a0d0041004188c2001001200028020421030b20032002410f6a4101100f1a2000200028020441016a220336020420060d000b0240200128020420012d00002205410176200541017122061b2205450d002001280208200141016a20061b21060240200028020820036b20054e0d0041004188c2001001200028020421030b200320062005100f1a2000200028020420056a3602040b200241106a240020000b02000b02000b1a00024020012d0024410171450d002001412c6a280200102a0b0bae0201047f230041206b220324000240024020020d00200341146a41003602002003420037020c200341086a410472210402402000280208200028020422026b41034b0d00410041d9c4001001200028020421020b200341086a20024104100f1a2000200028020441046a3602042000200410611a02402001280210417f460d0020012802042205450d00200521020240200141086a28020022002005460d000340200041486a21020240200041786a22042802002206417f460d00200341186a200041486a20064102744188c5006a2802001101000b2004417f3602002002210020052002470d000b200128020421020b200120053602082002102a0b2001200329030837020020014100360210200141086a20032903103702000c010b410041a0c50010010b200341206a24000b870303027f017e047f230041106b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22033602042004200641ff0071200541ff0171220574ad842104200541076a2105200321032006418001710d000b0240024020012802042205200128020022076b41386d22062004a722034f0d002001200320066b1062200128020421050c010b200620034d0d0002402007200341386c6a22082005460d000340200541486a21030240200541786a22062802002207417f460d00200241086a200541486a20074102744188c5006a2802001101000b2006417f3602002003210520082003470d000b0b20012008360204200821050b0240200128020022032005460d0003402000200310631a02402000280208200028020422066b41014b0d00410041d9c4001001200028020421060b200341346a20064102100f1a2000200028020441026a360204200341386a22032005470d000b0b200241106a240020000ba105010c7f230041106b2202240002400240024020002802082203200028020422046b41386d2001490d000340200441306a2203420037020020044200370200200441286a4200370200200441186a4200370200200441106a4200370200200441086a4200370200200441206a4200370200200341003602002000200028020441386a22043602042001417f6a22010d000c020b0b2004200028020022056b41386d220620016a220741a592c9244f0d0141a492c924210402400240200320056b41386d22034191c9a4124b0d0020072003410174220420042007491b22040d0041002104410021030c010b200441386c102921030b2003200441386c6a21082003200641386c6a22092104034020044200370200200441286a4200370200200441186a4200370200200441106a4200370200200441086a4200370200200441206a4200370200200441306a4200370200200441386a21042001417f6a22010d000b024002402000280204220a20002802002205470d002000200836020820002004360204200020093602000c010b2005200a6b210b410021010340200920016a220341786a2206417f360200200341486a220741003a00000240200a20016a220541786a220c280200220d417f460d00200241086a2007200541486a200d4102744194c5006a2802001102002006200c2802003602000b2003417c6a2005417c6a2f01003b0100200b200141486a2201470d000b200020083602082000280204210320002004360204200028020021052000200920016a36020020032005460d000340200341486a21040240200341786a22012802002200417f460d002002200341486a20004102744188c5006a2802001101000b2001417f3602002004210320052004470d000b0b2005450d002005102a0b200241106a24000f0b2000102c000bdf0203027f017e037f230041306b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22073602042004200641ff0071200541ff0171220374ad842104200341076a2105200721032006418001710d000b024002402004a722030d00410021030340200220036a2106024020002802082007470d00410041d9c4001001200028020421070b200620074101100f1a2000200028020441016a2207360204200341016a22034121470d000b024020012802302203417f460d00200241286a200120034102744188c5006a2802001101000b2001200229030037000020014100360230200141206a200241206a2d00003a0000200141186a200241186a290300370000200141106a200241106a290300370000200141086a200241086a2903003700000c010b20002001200310670b200241306a240020000b4c0020012002290000370000200141206a200241206a2d00003a0000200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a2900003700000b4c0020012002290000370000200141206a200241206a2d00003a0000200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a2900003700000b7801017f20012002290200370200200141206a200241206a2f01003b0100200141186a200241186a290200370200200141106a200241106a290200370200200141086a200241086a2902003702002001412c6a2002412c6a22032802003602002001200229022437022420024200370224200341003602000be70401037f230041c0006b22032400024002402002417f6a220241014b0d000240024020020e020001000b20002802042102410021040340200341086a20046a2105024020002802082002470d00410041d9c4001001200028020421020b200520024101100f1a2000200028020441016a2202360204200441016a22044121470d000b024020012802302200417f460d00200341386a200120004102744188c5006a2802001101000b2001200329030837000020014101360230200141206a200341086a41206a2d00003a0000200141186a200341086a41186a290300370000200141106a200341086a41106a290300370000200141086a200341086a41086a2903003700000c020b200341346a41003602002003420037022c20002802042102410021040340200341086a20046a2105024020002802082002470d00410041d9c4001001200028020421020b200520024101100f1a2000200028020441016a2202360204200441016a22044121470d000b200341296a2104024020002802082002470d00410041d9c4001001200028020421020b200420024101100f1a2000200028020441016a36020420002003412c6a220210681a024020012802302200417f460d00200341386a200120004102744188c5006a2802001101000b200120032903083702002001410236023020012002290200370224200141206a200341086a41206a2f01003b0100200141186a200341086a41186a290300370200200141106a200341086a41106a290300370200200141086a200341086a41086a2903003702002001412c6a200241086a2802003602000c010b410041a0c50010010b200341c0006a24000ba00301057f230041206b2202240020024100360218200242003703102000200241106a10421a0240024002402002280214200228021022036b2204450d00200241086a410036020020024200370300200441704f0d02024002402004410a4b0d00200220044101743a0000200241017221050c010b200441106a4170712206102921052002200436020420022006410172360200200220053602080b0340200520032d00003a0000200541016a2105200341016a21032004417f6a22040d000b200541003a00000240024020012d00004101710d00200141003b01000c010b200128020841003a00002001410036020420012d0000410171450d002001280208102a200141003602000b20012002290300370200200141086a200241086a2802003602000c010b0240024020012d00004101710d00200141003b01000c010b200128020841003a00002001410036020420012d0000410171450d002001280208102a200141003602000b20014100360208200142003702000b024020022802102205450d00200220053602142005102a0b200241206a240020000f0b2002102b000b0beb0503004190c0000b796661696c656420746f20616c6c6f6361746520706167657300756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f7200746865206f6e6572726f7220616374696f6e2063616e6e6f742062652063616c6c6564206469726563746c790000000000000000004189c1000bd904000000000000006461746173747265616d20617474656d7074656420746f20777269746520706173742074686520656e64000a006665617475726520646967657374206163746976617465643a200070726f746f636f6c2066656174757265206973206e6f74206163746976617465640000000100000002000000030000006461746173747265616d20617474656d7074656420746f20777269746520706173742074686520656e6400000400000005000000060000006f626a6563742070617373656420746f206974657261746f725f746f206973206e6f7420696e206d756c74695f696e646578006572726f722072656164696e67206974657261746f720063616e6e6f7420637265617465206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e7472616374006f626a6563742070617373656420746f206d6f64696679206973206e6f7420696e206d756c74695f696e6465780063616e6e6f74206d6f64696679206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e747261637400757064617465722063616e6e6f74206368616e6765207072696d617279206b6579207768656e206d6f64696679696e6720616e206f626a656374006461746173747265616d20617474656d7074656420746f207265616420706173742074686520656e640067657400000700000008000000090000000a0000000b0000000c000000696e76616c69642076617269616e7420696e64657800756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f72000041000b04e8220000000000000000000000003d5251a1c9a3cd8d7baad33a381b9e09858e0503df1751181fd60202251c23fb04000000033b3d4b010000000446ce40fcba331770d4e40c1a69d054d3a9a5ed89ef08b50cc808e325010000000000ea3055024900000000000000000000000000 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":95932,"consumed":6881},"cpu_usage":{"last_ordinal":1262304003,"value_ex":267959,"consumed":2101},"ram_usage":199492} +DMLOG APPLIED_TRANSACTION 4 f6e310259a2df1180a080592a90630cfdbffbd90a5144d2fb46801bbaff3aaec04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e50100d0070000dc060000000000000000e01a0000000000000001010000010000000000ea3055378d583c2888f3564b4db37bfb52d74d038e54fcc63aeb57cf27b03c001e97a51a000000000000001a00000000000000010000000000ea30551a0000000000000002010000000000ea30550000000000ea305500000040258ab2c2010000000000ea305500000000a8ed3232cb99010000000000ea30550000be99010061736d010000000198011960000060027f7f0060037f7f7f0060047e7e7e7e017f6000017e60047f7e7e7f0060057f7f7f7f7f017f60037f7f7f017f60027f7f017f60027f7f017e60057f7f7f7f7f0060067e7e7e7e7f7f017f60017e0060027e7f0060047e7e7e7e0060037e7f7f017e60017f0060017f017f6000017f60027f7e0060047f7e7f7f0060037e7e7e0060037f7e7f0060047f7f7f7f0060027e7e0002f0052403656e760b64625f66696e645f693634000303656e760c656f73696f5f617373657274000103656e761063757272656e745f7265636569766572000403656e760561626f7274000003656e760d6173736572745f736861323536000203656e760b6173736572745f73686131000203656e760d6173736572745f736861353132000203656e76106173736572745f726970656d64313630000203656e7606736861323536000203656e76095f5f6173686c746933000503656e760473686131000203656e7606736861353132000203656e7609726970656d64313630000203656e760b7265636f7665725f6b6579000603656e76207365745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000103656e76066d656d637079000703656e76206765745f626c6f636b636861696e5f706172616d65746572735f7061636b6564000803656e76167365745f70726f706f7365645f70726f647563657273000903656e760c63757272656e745f74696d65000403656e76146765745f6163746976655f70726f647563657273000803656e76087072696e74735f6c000103656e76126173736572745f7265636f7665725f6b6579000a03656e760c64625f73746f72655f693634000b03656e760c726571756972655f61757468000c03656e760e7365745f70726976696c65676564000d03656e76137365745f7265736f757263655f6c696d697473000e03656e76197365745f70726f706f7365645f70726f6475636572735f6578000f03656e761370726561637469766174655f66656174757265001003656e76067072696e7473001003656e761469735f666561747572655f616374697661746564001103656e7610616374696f6e5f646174615f73697a65001203656e7610726561645f616374696f6e5f64617461000803656e7611656f73696f5f6173736572745f636f6465001303656e760a64625f6765745f693634000703656e760d64625f7570646174655f693634001403656e76087072696e7468657800010346450015111000111010100c100802101608020817010110011818181818181808011818181818080101180818181808000808010101080101010801010102080108020202020804050170010d0d05030100010616037f014180c0000b7f0041e2c5000b7f0041e2c5000b070901056170706c7900250912010041010b0c555657595a5b5d5e5f6465660aab8b0145040010280bdd03002000102d102420002001510440428080f9d4a98499dc9a7f200251044020002001103b05428080add68d959ba955200251044020002001103c05428080add68d95abd1ca00200251044020002001103d0542808080e8b2edc0d38b7f200251044020002001103e05428080add68db8baf154200251044020002001103f054280f8a6d4d2a8a1d3c1002002510440200020011040054280808080d4c4a2d942200251044020002001104105428080808080f798d9422002510440200020011044054280808080aefadeeaa47f2002510440200020011045054280808080b6f7d6d942200251044020002001104605428080b8f6a4979ad94220025104402000200110470542808080c093fad6d9422002510440200020011048054280808096cdebd4d942200251044020002001104c054280808080daac9bd6ba7f200251044020002001104e0542808080d0b2b3bb9932200251044020002001104f054290a9d9d9dd8c99d6ba7f2002510440200020011050052000428080808080c0ba98d500520440410042808080d9d3b3ed82ef0010200b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b05428080808080c0ba98d50020015104404280808080aefadeeaa47f2002510440410042818080d9d3b3ed82ef0010200b0b0b410010310b7201037f024020000d0041000f0b4100410028028c40200041107622016a220236028c404100410028028440220320006a410f6a4170712200360284400240200241107420004b0d004100200241016a36028c40200141016a21010b024020014000417f470d0041004190c00010010b20030b02000b3601017f230041106b2200410036020c4100200028020c280200410f6a417071220036028040410020003602844041003f0036028c400b3301027f2000410120001b2101024003402001102622000d01410021004100280284412202450d0120021100000c000b0b20000b0600200010270b05001003000b05001003000b0a0041002000370388410b4e01017f230041e0006b220124002001200141d8006a3602082001200141106a3602042001200141106a36020020012000102f1a200141106a200128020420012802006b100e200141e0006a24000ba20801027f02402000280208200028020422026b41074a0d0041004190c1001001200028020421020b200220014108100f1a2000200028020441086a2202360204200141086a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001410c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141106a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141146a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141186a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001411c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141206a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141246a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141286a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001412c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141306a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141346a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141386a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a22023602042001413c6a21030240200028020820026b41034a0d0041004190c1001001200028020421020b200220034104100f1a2000200028020441046a2202360204200141c0006a21030240200028020820026b41014a0d0041004190c1001001200028020421020b200220034102100f1a2000200028020441026a2202360204200141c2006a21010240200028020820026b41014a0d0041004190c1001001200028020421020b200220014102100f1a2000200028020441026a36020420000bfa0103017f027e017f230041306b2203240020012002200341106a1008420021044110210141002102420021050340200341106a20026a21060240024020014102490d002005420886200420063100008422044238888421052001417f6a2101200442088621040c010b024020014101460d00410041a9c00010010b200020053703082000200420063100008437030041102101200041106a210042002104420021050b200241016a22024120470d000b024020014110460d00024020014102490d00200320042005200141037441786a1009200341086a2903002105200329030021040b20002004370300200020053703080b200341306a24000b02000b970503017f017e047f230041f0006b22032400200341206a4100360200200342003703182003427f37031020032000290300220437030820032004370300024002402004200442808080809aecb4ee312001100022004100480d00024020032000103322002802302003460d00410041c0c20010010b2003200236023020032000200341306a10340c010b024020041002510d004100418ac30010010b41c000102922004200370310200041286a22054200370300200041206a22064200370300200041186a220742003703002000200336023020002001370300200341306a20022802002208200228020420086b10302005200341306a41186a2903003703002006200341306a41106a29030037030020072003290338370300200020032903303703102003200341306a41286a3602682003200341306a360260200341306a20004108100f1a2003200341306a410872360264200341e0006a200041106a10351a2000200329030842808080809aecb4ee31200120002903002204200341306a412810162205360234024020042003290310540d002003427e200442017c2004427d561b3703100b200320003602602003200029030022043703302003200536022c02400240200328021c220220032802204f0d00200220053602102002200437030820034100360260200220003602002003200241186a36021c0c010b200341186a200341e0006a200341306a2003412c6a10360b20032802602100200341003602602000450d002000102a0b024020032802182205450d0002400240200328021c22002005470d00200521000c010b0340200041686a220028020021022000410036020002402002450d002002102a0b20052000470d000b200328021821000b2003200536021c2000102a0b200341f0006a24000b840603097f027e017f230041e0006b220221032002240002400240200028021822042000411c6a2802002205460d0002400340200541786a2802002001460d012004200541686a2205470d000c020b0b20042005460d00200541686a28020021060c010b024002400240024020014100410010212205417f4a0d00410041f3c20010010c010b2005418104490d010b200510262107410121080c010b20022005410f6a4170716b22072400410021080b20012007200510211a41c0001029220642003703102006420037030020062000360230200641186a4200370300200641206a4200370300200641286a42003703000240200541074b0d00410041d9c40010010b200620074108100f1a200741086a21040240200541786a411f4b0d00410041d9c40010010b200041186a2109200641106a210a200341c0006a20044120100f1a4200210b41102105200341206a2102410021044200210c0340200341c0006a20046a210d0240024020054102490d00200c420886200b200d31000084220b42388884210c2005417f6a2105200b420886210b0c010b024020054101460d00410041b6c50010010b2002200c3703082002200b200d3100008437030041102105200241106a21024200210b4200210c0b200441016a22044120470d000b024020054110460d00024020054102490d00200341086a200b200c200541037441786a1009200341106a290300210c2003290308210b0b2002200b3703002002200c3703080b200a2003290320370300200a41086a2003290328370300200a41186a200341206a41186a290300370300200a41106a200341206a41106a290300370300200620013602342003200636022020032006290300220b3703402003200136021c02400240200028021c2205200041206a2802004f0d00200520013602102005200b37030820034100360220200520063602002000200541186a36021c0c010b2009200341206a200341c0006a2003411c6a10360b02402008450d00200710270b20032802202105200341003602202005450d002005102a0b200341e0006a240020060b980203027f017e017f230041206b2203210420032400024020012802302000460d00410041bdc30010010b024010022000290300510d00410041ebc30010010b200129030021052004200228020022022802002206200228020420066b1030200141286a200441186a290300370300200141206a200441106a290300370300200141186a200429030837030020012004290300370310200141106a2102024020052001290300510d004100419ec40010010b200341506a220324002004200341286a36020820042003360200200320014108100f1a2004200341086a3602042004200210351a20012802344200200341281022024020052000290310540d002000427e200542017c2005427d561b3703100b200441206a24000bd20303017f027e017f230041206b220224002002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722054108763a0016200220054110763a0015200220054118763a001420022004a722053a0007200220054108763a0006200220054110763a0005200220054118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c001002402000280208200028020422016b411f4a0d0041004188c2001001200028020421010b200120024120100f1a2000200028020441206a360204200241206a240020000b9a0301057f0240024002402000280204200028020022046b41186d220541016a220641abd5aad5004f0d0041aad5aad500210702400240200028020820046b41186d220441d4aad52a4b0d0020062004410174220720072006491b22070d0041002107410021040c010b200741186c102921040b20012802002106200141003602002004200541186c22086a2201200328020036021020012002290300370308200120063602002004200741186c6a2105200141186a21062000280204220220002802002207460d01200420086a41686a21010340200241686a220428020021032004410036020020012003360200200141086a200241706a2202290300370300200141106a200241086a280200360200200141686a21012004210220072004470d000b200141186a210120002802042107200028020021040c020b2000102c000b200721040b200020053602082000200636020420002001360200024020072004460d000340200741686a220728020021012007410036020002402001450d002001102a0b20042007470d000b0b02402004450d002004102a0b0bd00203047f017e017f230041106b220224004100210320004100360208200042003702002002410036020020012802042204200128020022056b410575ad21060340200341016a2103200642078822064200520d000b2002200336020002400240024020052004460d0003402002200341086a3602002003410c6a2103200541186a2802002207ad21060340200341016a2103200642078822064200520d000b20022003417c6a3602002007417f460d022002200336020020022005410c6a10511a20022802002103200541206a22052004470d000b20002802002105200028020421070c020b41002105410021070c010b1052000b024002402003200720056b22074d0d002000200320076b1043200028020021050c010b200320074f0d002000200520036a3602040b2002200536020420022005360200200220002802043602082002200110531a200241106a24000baf0302017f027e230041206b22022400200029030010172002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722004108763a0016200220004110763a0015200220004118763a001420022004a722003a0007200220004108763a0006200220004110763a0005200220004118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c00102002101b41bdc100101c2001103941bbc100101c200241206a24000b9c0303017f027e017f230041206b220124002001200041186a29030022023c00172001200041086a29030022034220883c0003200120034228883c0002200120034230883c0001200120034238883c0000200120024220883c001320012002a722044108763a0016200120044110763a0015200120044118763a001420012003a722043a0007200120044108763a0006200120044110763a0005200120044118763a0004200120002903002203423886200342288642808080808080c0ff0083842003421886428080808080e03f8320034208864280808080f01f838484200342088842808080f80f832003421888428080fc07838420034228884280fe03832003423888848484370308200120002903102203423886200342288642808080808080c0ff0083842003421886428080808080e03f8320034208864280808080f01f838484200342088842808080f80f832003421888428080fc07838420034228884280fe03832003423888848484370318200120024230883c0011200120024228883c0012200120024238883c0010200141201023200141206a24000ba70303017f027e017f230041206b220224002002200141186a29030022033c00172002200141086a29030022044220883c0003200220044228883c0002200220044230883c0001200220044238883c0000200220034220883c001320022003a722054108763a0016200220054110763a0015200220054118763a001420022004a722053a0007200220054108763a0006200220054110763a0005200220054118763a0004200220012903002204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370308200220012903102204423886200442288642808080808080c0ff0083842004421886428080808080e03f8320044208864280808080f01f838484200442088842808080f80f832004421888428080fc07838420044228884280fe03832004423888848484370318200220034230883c0011200220034228883c0012200220034238883c001002402002101d0d00410041d8c10010010b200241206a24000bb90101047f230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a20034200370300200241086a2102024020044178714108470d00410041d9c40010010b200320024108100f1a200341106a24000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000b4401037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b200324000bc90201047f230041306b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360224200320023602202003200220046a2205360228200342003703180240200441074b0d00410041d9c400100120032802282105200328022421020b200341186a20024108100f1a2003200241086a2202360224024020052002470d00410041d9c400100120032802282105200328022421020b200341176a20024101100f1a2003200241016a2202360224024020052002470d00410041d9c4001001200328022421020b200341166a20024101100f1a2003200241016a3602242003410036021020034200370308200341206a200341086a10421a024020032802082202450d002003200236020c2002102a0b200341306a24000bff0103017f017e047f2000280204210242002103410021040340024020022000280208490d0041004183c5001001200028020421020b20022d000021052000200241016a22063602042003200541ff0071200441ff0171220274ad842103200241076a2104200621022005418001710d000b0240024020012802042205200128020022026b22072003a722044f0d002001200420076b10432000280204210620012802042105200128020021020c010b200720044d0d002001200220046a22053602040b0240200028020820066b200520026b22054f0d00410041d9c4001001200028020421060b200220062005100f1a2000200028020420056a36020420000b980201057f02400240024020002802082202200028020422036b2001490d000340200341003a00002000200028020441016a22033602042001417f6a22010d000c020b0b2003200028020022046b220520016a2206417f4c0d0141ffffffff07210302400240200220046b220241feffffff034b0d0020062002410174220320032006491b22030d0041002103410021020c010b2003102921020b200220036a2106200220056a220421030340200341003a0000200341016a21032001417f6a22010d000b20042000280204200028020022016b22026b2104024020024101480d00200420012002100f1a200028020021010b2000200636020820002003360204200020043602002001450d002001102a0b0f0b2000102c000bb20202037f017e23004180016b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360254200320023602502003200220046a360258200342003703480240200441074b0d00410041d9c4001001200328025421020b200341c8006a20024108100f1a2003200241086a3602542003410036024020034200370338200341d0006a200341386a10421a200341086a41086a200341d0006a41086a2802002202360200200341306a2002360200200320032903502205370308200320013703202003200037031820032005370328200341186a2003290348200341386a1032024020032802382202450d002003200236023c2002102a0b20034180016a24000b4c01037f2300220221030240101e2204450d00024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b410041d5c0001001200324000bcf0102047f017e230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a200241086a2102024020044108470d00410041d9c40010010b200341076a20024101100f1a2003290308210620032d0007210420001017200620044100471018200341106a24000baa0202047f047e230041206b2202210320022400024002400240101e22040d002003420037031841002102200341186a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370318200341186a2105200441074b0d010b410041d9c40010010b200520024108100f1a200241086a21050240200441787122044108470d00410041d9c40010010b200341106a20054108100f1a200241106a2105024020044110470d00410041d9c40010010b200341086a20054108100f1a200241186a2102024020044118470d00410041d9c40010010b200320024108100f1a200329030021062003290308210720032903102108200329031821092000101720092008200720061019200341206a24000ba103010b7f230041306b2202210320022400410021040240101e2205450d00024002402005418004490d002005102621040c010b20022005410f6a4170716b220424000b20042005101f1a0b20032004360214200320043602102003200420056a3602182003410036020820034200370300200341106a200310491a20001017200341206a20031037420120032802202204200328022420046b101a1a024020032802202204450d00200320043602242004102a0b024020032802002206450d0002400240200328020422072006470d00200621040c010b03402007220441606a21070240200441786a2208280200417f460d002004416c6a2209280200220a450d00200a21050240200441706a220b2802002204200a460d000340200441486a21050240200441786a2202280200220c417f460d00200341206a200441486a200c4102744188c5006a2802001101000b2002417f36020020052104200a2005470d000b200928020021050b200b200a3602002005102a0b2008417f36020020072006470d000b200328020021040b200320063602042004102a0b200341306a24000bcc0303027f017e097f230041206b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22033602042004200641ff0071200541ff0171220574ad842104200541076a2105200321032006418001710d000b0240024020012802042207200128020022056b41057522062004a722034f0d002001200320066b104a200128020421070c010b200620034d0d000240200520034105746a22082007460d0003402007220341606a21070240200341786a2209280200417f460d002003416c6a220a280200220b450d00200b21060240200341706a220c2802002203200b460d000340200341486a21060240200341786a2205280200220d417f460d00200241186a200341486a200d4102744188c5006a2802001101000b2005417f36020020062103200b2006470d000b200a28020021060b200c200b3602002006102a0b2009417f36020020072008470d000b0b20012008360204200821070b0240200128020022032007460d00034020022000360208200220033602102002200341086a360214200241106a200241086a104b200341206a22032007470d000b0b200241206a240020000b9f06030a7f017e037f230041106b220224000240024020002802082203200028020422046b4105752001490d000340200441186a2203420037030020044200370300200441106a4200370300200441086a4200370300200341003602002000200028020441206a22043602042001417f6a22010d000c020b0b02400240024002402004200028020022056b410575220620016a220741808080c0004f0d0041ffffff3f210402400240200320056b220341057541feffff1f4b0d00024020072003410475220420042007491b22040d0041002104410021030c020b200441808080c0004f0d030b2004410574102921030b200320044105746a2108200320064105746a22092104034020044200370300200441186a4200370300200441106a4200370300200441086a4200370300200441206a21042001417f6a22010d000b2000280204220a20002802002206460d022006200a6b210b410021050340200920056a220141786a2206417f360200200a20056a220341606a290300210c200141686a220741003a0000200141606a200c3703000240200341786a280200220d417f460d00200141706a220e42003702002001416c6a220f4100360200200e200341706a280200360200200f2003416c6a220e280200360200200141746a200341746a22012802003602002007200341686a2802003602002006200d36020020014100360200200e42003702000b200b200541606a2205470d000b200920056a2109200028020421062000280200210d0c030b2000102c000b1003000b2006210d0b20002008360208200020043602042000200936020002402006200d460d0003402006220441606a21060240200441786a2207280200417f460d002004416c6a220e2802002200450d00200021010240200441706a220f28020022042000460d000340200441486a21010240200441786a22032802002205417f460d00200241086a200441486a20054102744188c5006a2802001101000b2003417f3602002001210420002001470d000b200e28020021010b200f20003602002001102a0b2007417f3602002006200d470d000b0b200d450d00200d102a0b200241106a24000bca0102037f017e20002802002102024020012802002203280208200328020422046b41074b0d00410041d9c4001001200328020421040b200220044108100f1a2003200328020441086a3602042000280204210220012802002201280204210342002105410021040340024020032001280208490d0041004183c5001001200128020421030b20032d000021002001200341016a22033602042005200041ff0071200441ff0171220474ad842105200441076a2104200321032000418001710d000b200120022005a710600b890101037f230041e0006b220221032002240002400240101e22040d00410021020c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a0b20032002360254200320023602502003200220046a360258200341d0006a200341086a104d1a20001017200341086a102e200341e0006a24000ba20801027f02402000280208200028020422026b41074b0d00410041d9c4001001200028020421020b200120024108100f1a2000200028020441086a2202360204200141086a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001410c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141106a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141146a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141186a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001411c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141206a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141246a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141286a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001412c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141306a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141346a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141386a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a22023602042001413c6a21030240200028020820026b41034b0d00410041d9c4001001200028020421020b200320024104100f1a2000200028020441046a2202360204200141c0006a21030240200028020820026b41014b0d00410041d9c4001001200028020421020b200320024102100f1a2000200028020441026a2202360204200141c2006a21010240200028020820026b41014b0d00410041d9c4001001200028020421020b200120024102100f1a2000200028020441026a36020420000b940101047f230041106b2202210320022400024002400240101e22040d002003420037030841002102200341086a21050c010b024002402004418004490d002004102621020c010b20022004410f6a4170716b220224000b20022004101f1a20034200370308200341086a2105200441074b0d010b410041d9c40010010b200520024108100f1a20032903081017200341106a24000b8c0405047f017e037f017e017f230041f0006b220221032002240002400240101e22040d00410021050c010b024002402004418004490d002004102621050c010b20022004410f6a4170716b220524000b20052004101f1a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d00410041d9c40010010b200520046a2107200341d0006a20054120100f1a200541206a2108200341306a2109410021044200210a0340200341d0006a20046a210b0240024020024102490d00200a4208862006200b31000084220642388884210a2002417f6a2102200642088621060c010b024020024101460d00410041b6c50010010b2009200a37030820092006200b3100008437030041102102200941106a2109420021064200210a0b200441016a22044120470d000b024020024110460d00024020024102490d0020032006200a200241037441786a1009200341086a290300210a200329030021060b200920063703002009200a3703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a2903003703002003200329033837031820032003290330370310200341d0006a41186a2007360200200341e4006a2008360200200320053602602003200137035820032000370350200341d0006a200341106a1038200341f0006a24000bc80303047f027e017f230041f0006b220221032002240002400240101e22040d00410021050c010b024002402004418004490d002004102621050c010b20022004410f6a4170716b220524000b20052004101f1a0b42002106200341286a420037030041102102200341106a41106a4200370300200342003703182003420037031002402004411f4b0d00410041d9c40010010b200341d0006a20054120100f1a200341306a210541002104420021070340200341d0006a20046a21080240024020024102490d002007420886200620083100008422064238888421072002417f6a2102200642088621060c010b024020024101460d00410041b6c50010010b200520073703082005200620083100008437030041102102200541106a210542002106420021070b200441016a22044120470d000b024020024110460d00024020024102490d00200320062007200241037441786a1009200341086a2903002107200329030021060b20052006370300200520073703080b200341106a41186a200341306a41186a290300370300200341106a41106a200341306a41106a29030037030020032003290338370318200320032903303703102002200341106a103a200341f0006a24000bd50103037f017e017f230041106b2202240020012802042203200128020022046b41386dad2105200028020021010340200141016a2101200542078822054200520d000b200020013602000240024020042003460d00034020042802302206ad21050340200141016a2101200542078822054200520d000b20002001360200200220003602002006417f460d0220022002360208200241086a2004200641027441fcc1006a2802001101002000200028020041026a2201360200200441386a22042003470d000b0b200241106a240020000f0b1052000b05001003000bfe0103017f017e037f230041106b22022400200128020420012802006b410575ad21032000280204210403402003a721052002200342078822034200522206410774200541ff0071723a000f0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410f6a4101100f1a2000200028020441016a220436020420060d000b02402001280200220520012802042206460d0003400240200028020820046b41074a0d0041004188c2001001200028020421040b200420054108100f1a2000200028020441086a3602042000200541086a10541a200541206a22052006460d01200028020421040c000b0b200241106a240020000bdd0103027f017e027f230041106b22022400200028020421032001350210210403402004a721052002200442078822044200522206410774200541ff0071723a000f0240200028020820036b41004a0d0041004188c2001001200028020421030b20032002410f6a4101100f1a2000200028020441016a220336020420060d000b02402001280210417f460d00200141046a21050240200028020820036b41034a0d0041004188c2001001200028020421030b200320014104100f1a2000200028020441046a3602042000200510581a200241106a240020000f0b1052000b170020002802002802002200200028020041216a3602000b170020002802002802002200200028020041216a3602000b7602017f017e20002802002802002202200228020041226a2200360200200141286a350200420020012d00244101711b21030340200041016a2100200342078822034200520d000b200220003602000240200128022820012d0024220141017620014101711b2201450d002002200120006a3602000b0b990303017f017e047f230041106b22022400200128020420012802006b41386dad21032000280204210403402003a721052002200342078822034200522206410774200541ff0071723a000f0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410f6a4101100f1a2000200028020441016a220436020420060d000b024002402001280200220720012802042201460d0003402007350230210303402003a721052002200342078822034200522206410774200541ff0071723a000e0240200028020820046b41004a0d0041004188c2001001200028020421040b20042002410e6a4101100f1a2000200028020441016a220436020420060d000b2002200036020020072802302204417f460d0220022002360208200241086a2007200441027441b4c2006a280200110100200741346a210502402000280208200028020422046b41014a0d0041004188c2001001200028020421040b200420054102100f1a2000200028020441026a2204360204200741386a22072001470d000b0b200241106a240020000f0b1052000b6401037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b0b6401037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b0baa0101037f200028020028020022002802042102410021030340200120036a21040240200028020820026b41004a0d0041004188c2001001200028020421020b200220044101100f1a2000200028020441016a2202360204200341016a22034121470d000b200141216a21030240200028020820026b41004a0d0041004188c2001001200028020421020b200220034101100f1a2000200028020441016a3602042000200141246a105c1a0bfd0103027f017e027f230041106b22022400200128020420012d0000220341017620034101711bad21042000280204210303402004a721052002200442078822044200522206410774200541ff0071723a000f0240200028020820036b41004a0d0041004188c2001001200028020421030b20032002410f6a4101100f1a2000200028020441016a220336020420060d000b0240200128020420012d00002205410176200541017122061b2205450d002001280208200141016a20061b21060240200028020820036b20054e0d0041004188c2001001200028020421030b200320062005100f1a2000200028020420056a3602040b200241106a240020000b02000b02000b1a00024020012d0024410171450d002001412c6a280200102a0b0bae0201047f230041206b220324000240024020020d00200341146a41003602002003420037020c200341086a410472210402402000280208200028020422026b41034b0d00410041d9c4001001200028020421020b200341086a20024104100f1a2000200028020441046a3602042000200410611a02402001280210417f460d0020012802042205450d00200521020240200141086a28020022002005460d000340200041486a21020240200041786a22042802002206417f460d00200341186a200041486a20064102744188c5006a2802001101000b2004417f3602002002210020052002470d000b200128020421020b200120053602082002102a0b2001200329030837020020014100360210200141086a20032903103702000c010b410041a0c50010010b200341206a24000b870303027f017e047f230041106b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22033602042004200641ff0071200541ff0171220574ad842104200541076a2105200321032006418001710d000b0240024020012802042205200128020022076b41386d22062004a722034f0d002001200320066b1062200128020421050c010b200620034d0d0002402007200341386c6a22082005460d000340200541486a21030240200541786a22062802002207417f460d00200241086a200541486a20074102744188c5006a2802001101000b2006417f3602002003210520082003470d000b0b20012008360204200821050b0240200128020022032005460d0003402000200310631a02402000280208200028020422066b41014b0d00410041d9c4001001200028020421060b200341346a20064102100f1a2000200028020441026a360204200341386a22032005470d000b0b200241106a240020000ba105010c7f230041106b2202240002400240024020002802082203200028020422046b41386d2001490d000340200441306a2203420037020020044200370200200441286a4200370200200441186a4200370200200441106a4200370200200441086a4200370200200441206a4200370200200341003602002000200028020441386a22043602042001417f6a22010d000c020b0b2004200028020022056b41386d220620016a220741a592c9244f0d0141a492c924210402400240200320056b41386d22034191c9a4124b0d0020072003410174220420042007491b22040d0041002104410021030c010b200441386c102921030b2003200441386c6a21082003200641386c6a22092104034020044200370200200441286a4200370200200441186a4200370200200441106a4200370200200441086a4200370200200441206a4200370200200441306a4200370200200441386a21042001417f6a22010d000b024002402000280204220a20002802002205470d002000200836020820002004360204200020093602000c010b2005200a6b210b410021010340200920016a220341786a2206417f360200200341486a220741003a00000240200a20016a220541786a220c280200220d417f460d00200241086a2007200541486a200d4102744194c5006a2802001102002006200c2802003602000b2003417c6a2005417c6a2f01003b0100200b200141486a2201470d000b200020083602082000280204210320002004360204200028020021052000200920016a36020020032005460d000340200341486a21040240200341786a22012802002200417f460d002002200341486a20004102744188c5006a2802001101000b2001417f3602002004210320052004470d000b0b2005450d002005102a0b200241106a24000f0b2000102c000bdf0203027f017e037f230041306b220224002000280204210342002104410021050340024020032000280208490d0041004183c5001001200028020421030b20032d000021062000200341016a22073602042004200641ff0071200541ff0171220374ad842104200341076a2105200721032006418001710d000b024002402004a722030d00410021030340200220036a2106024020002802082007470d00410041d9c4001001200028020421070b200620074101100f1a2000200028020441016a2207360204200341016a22034121470d000b024020012802302203417f460d00200241286a200120034102744188c5006a2802001101000b2001200229030037000020014100360230200141206a200241206a2d00003a0000200141186a200241186a290300370000200141106a200241106a290300370000200141086a200241086a2903003700000c010b20002001200310670b200241306a240020000b4c0020012002290000370000200141206a200241206a2d00003a0000200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a2900003700000b4c0020012002290000370000200141206a200241206a2d00003a0000200141186a200241186a290000370000200141106a200241106a290000370000200141086a200241086a2900003700000b7801017f20012002290200370200200141206a200241206a2f01003b0100200141186a200241186a290200370200200141106a200241106a290200370200200141086a200241086a2902003702002001412c6a2002412c6a22032802003602002001200229022437022420024200370224200341003602000be70401037f230041c0006b22032400024002402002417f6a220241014b0d000240024020020e020001000b20002802042102410021040340200341086a20046a2105024020002802082002470d00410041d9c4001001200028020421020b200520024101100f1a2000200028020441016a2202360204200441016a22044121470d000b024020012802302200417f460d00200341386a200120004102744188c5006a2802001101000b2001200329030837000020014101360230200141206a200341086a41206a2d00003a0000200141186a200341086a41186a290300370000200141106a200341086a41106a290300370000200141086a200341086a41086a2903003700000c020b200341346a41003602002003420037022c20002802042102410021040340200341086a20046a2105024020002802082002470d00410041d9c4001001200028020421020b200520024101100f1a2000200028020441016a2202360204200441016a22044121470d000b200341296a2104024020002802082002470d00410041d9c4001001200028020421020b200420024101100f1a2000200028020441016a36020420002003412c6a220210681a024020012802302200417f460d00200341386a200120004102744188c5006a2802001101000b200120032903083702002001410236023020012002290200370224200141206a200341086a41206a2f01003b0100200141186a200341086a41186a290300370200200141106a200341086a41106a290300370200200141086a200341086a41086a2903003702002001412c6a200241086a2802003602000c010b410041a0c50010010b200341c0006a24000ba00301057f230041206b2202240020024100360218200242003703102000200241106a10421a0240024002402002280214200228021022036b2204450d00200241086a410036020020024200370300200441704f0d02024002402004410a4b0d00200220044101743a0000200241017221050c010b200441106a4170712206102921052002200436020420022006410172360200200220053602080b0340200520032d00003a0000200541016a2105200341016a21032004417f6a22040d000b200541003a00000240024020012d00004101710d00200141003b01000c010b200128020841003a00002001410036020420012d0000410171450d002001280208102a200141003602000b20012002290300370200200141086a200241086a2802003602000c010b0240024020012d00004101710d00200141003b01000c010b200128020841003a00002001410036020420012d0000410171450d002001280208102a200141003602000b20014100360208200142003702000b024020022802102205450d00200220053602142005102a0b200241206a240020000f0b2002102b000b0beb0503004190c0000b796661696c656420746f20616c6c6f6361746520706167657300756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f7200746865206f6e6572726f7220616374696f6e2063616e6e6f742062652063616c6c6564206469726563746c790000000000000000004189c1000bd904000000000000006461746173747265616d20617474656d7074656420746f20777269746520706173742074686520656e64000a006665617475726520646967657374206163746976617465643a200070726f746f636f6c2066656174757265206973206e6f74206163746976617465640000000100000002000000030000006461746173747265616d20617474656d7074656420746f20777269746520706173742074686520656e6400000400000005000000060000006f626a6563742070617373656420746f206974657261746f725f746f206973206e6f7420696e206d756c74695f696e646578006572726f722072656164696e67206974657261746f720063616e6e6f7420637265617465206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e7472616374006f626a6563742070617373656420746f206d6f64696679206973206e6f7420696e206d756c74695f696e6465780063616e6e6f74206d6f64696679206f626a6563747320696e207461626c65206f6620616e6f7468657220636f6e747261637400757064617465722063616e6e6f74206368616e6765207072696d617279206b6579207768656e206d6f64696679696e6720616e206f626a656374006461746173747265616d20617474656d7074656420746f207265616420706173742074686520656e640067657400000700000008000000090000000a0000000b0000000c000000696e76616c69642076617269616e7420696e64657800756e6578706563746564206572726f7220696e2066697865645f627974657320636f6e7374727563746f72000041000b04e822000000000000000000000000f6e310259a2df1180a080592a90630cfdbffbd90a5144d2fb46801bbaff3aaec04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e5010000000000ea3055024900000000000000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG RAM_OP 0 eosio abi update setabi eosio 199629 137 DMLOG DB_OP UPD 0 eosio:eosio eosio eosio abihash eosio 0000000000ea3055d7abd75d188060de8a01ab2672d1cc2cd768fddc56203181b43685cc11f5ce46:0000000000ea3055fc470c7761cfe2530d91ab199fc6326b456e254a57fcc882544eb4c0e488fd39 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":101210,"consumed":7921},"cpu_usage":{"last_ordinal":1262304003,"value_ex":267959,"consumed":4101},"ram_usage":199629} -DMLOG APPLIED_TRANSACTION 4 befaff75b7a38d724c06bd3cf84cec04cb9b771d261f3937b82f0f29a6ecd12c04000000033b3d4b010000000446ce40fcba331770d4e40c1a69d054d3a9a5ed89ef08b50cc808e3250100d00700008201000000000000000010040000000000000001010000010000000000ea30552deb8b0eef2f2bfd027d20727a96e4b30eb6ccdc27488670d57bf488395c48fc1a000000000000001a00000000000000010000000000ea30551a0000000000000002020000000000ea30550000000000ea305500000000b863b2c2010000000000ea305500000000a8ed323293120000000000ea305589120e656f73696f3a3a6162692f312e320117626c6f636b5f7369676e696e675f617574686f726974792276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f763019086162695f686173680002056f776e6572046e616d6504686173680b636865636b73756d32353608616374697661746500010e666561747572655f6469676573740b636865636b73756d32353609617574686f726974790004097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d086163636f756e7473197065726d697373696f6e5f6c6576656c5f7765696768745b5d0577616974730d776169745f7765696768745b5d1a626c6f636b5f7369676e696e675f617574686f726974795f76300002097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d15626c6f636b636861696e5f706172616d65746572730011136d61785f626c6f636b5f6e65745f75736167650675696e7436341a7461726765745f626c6f636b5f6e65745f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6e65745f75736167650675696e7433321e626173655f7065725f7472616e73616374696f6e5f6e65745f75736167650675696e743332106e65745f75736167655f6c65657761790675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f6e756d0675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f64656e0675696e743332136d61785f626c6f636b5f6370755f75736167650675696e7433321a7461726765745f626c6f636b5f6370755f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6370755f75736167650675696e743332196d696e5f7472616e73616374696f6e5f6370755f75736167650675696e743332186d61785f7472616e73616374696f6e5f6c69666574696d650675696e7433321e64656665727265645f7472785f65787069726174696f6e5f77696e646f770675696e743332156d61785f7472616e73616374696f6e5f64656c61790675696e743332166d61785f696e6c696e655f616374696f6e5f73697a650675696e743332176d61785f696e6c696e655f616374696f6e5f64657074680675696e743136136d61785f617574686f726974795f64657074680675696e7431360b63616e63656c64656c617900020e63616e63656c696e675f61757468107065726d697373696f6e5f6c6576656c067472785f69640b636865636b73756d3235360a64656c657465617574680002076163636f756e74046e616d650a7065726d697373696f6e046e616d650a6b65795f7765696768740002036b65790a7075626c69635f6b6579067765696768740675696e743136086c696e6b617574680004076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650b726571756972656d656e74046e616d650a6e65776163636f756e7400040763726561746f72046e616d65046e616d65046e616d65056f776e657209617574686f726974790661637469766509617574686f72697479076f6e6572726f7200020973656e6465725f69640775696e743132380873656e745f747278056279746573107065726d697373696f6e5f6c6576656c0002056163746f72046e616d650a7065726d697373696f6e046e616d65177065726d697373696f6e5f6c6576656c5f77656967687400020a7065726d697373696f6e107065726d697373696f6e5f6c6576656c067765696768740675696e7431361270726f64756365725f617574686f7269747900020d70726f64756365725f6e616d65046e616d6509617574686f7269747917626c6f636b5f7369676e696e675f617574686f726974790c72657161637469766174656400010e666561747572655f6469676573740b636865636b73756d323536077265716175746800010466726f6d046e616d65067365746162690002076163636f756e74046e616d65036162690562797465730a736574616c696d6974730004076163636f756e74046e616d650972616d5f627974657305696e7436340a6e65745f77656967687405696e7436340a6370755f77656967687405696e74363407736574636f64650004076163636f756e74046e616d6506766d747970650575696e743809766d76657273696f6e0575696e743804636f646505627974657309736574706172616d73000106706172616d7315626c6f636b636861696e5f706172616d657465727307736574707269760002076163636f756e74046e616d650769735f707269760575696e74380873657470726f64730001087363686564756c651470726f64756365725f617574686f726974795b5d0a756e6c696e6b617574680003076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650a757064617465617574680004076163636f756e74046e616d650a7065726d697373696f6e046e616d6506706172656e74046e616d65046175746809617574686f726974790b776169745f776569676874000208776169745f7365630675696e743332067765696768740675696e743136100000002a9bed32320861637469766174650000bc892a4585a6410b63616e63656c64656c6179000040cbdaa8aca24a0a64656c65746561757468000000002d6b03a78b086c696e6b617574680000409e9a2264b89a0a6e65776163636f756e7400000000e0d27bd5a4076f6e6572726f7200905436db6564acba0c72657161637469766174656400000000a0656dacba07726571617574680000000000b863b2c206736574616269000000ce4eba68b2c20a736574616c696d6974730000000040258ab2c207736574636f6465000000c0d25c53b3c209736574706172616d730000000060bb5bb3c207736574707269760000000038d15bb3c20873657470726f6473000040cbdac0e9e2d40a756e6c696e6b61757468000040cbdaa86c52d50a757064617465617574680001000000a061d3dc31036936340000086162695f68617368000000012276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f7630011a626c6f636b5f7369676e696e675f617574686f726974795f76300000000000000000000000befaff75b7a38d724c06bd3cf84cec04cb9b771d261f3937b82f0f29a6ecd12c04000000033b3d4b010000000446ce40fcba331770d4e40c1a69d054d3a9a5ed89ef08b50cc808e325010000000000ea3055890000000000000000000000000000 -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":79733334,"consumed":9568},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":351659723,"consumed":42101},"pending_net_usage":7920,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":145068889,"consumed":8000},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":382895892,"consumed":4449},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} -DMLOG ACCEPTED_BLOCK 4 04000000040000000300000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010003000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b52d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b832a8006b631c33ec6afc9ab302513af7c26d7d5bd2a3801f269dd2bf1d13b540300000000000000010000000000ea305504000000010000000000ea305503000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000446ce40fcba331770d4e40c1a69d054d3a9a5ed89ef08b50cc808e325033b3d4b0000000000ea30550000000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b5dafd0f0596077e5010e7d7876a42e26a54669cb6ab0f1f073bf87b3d88a3043bc48e1625ffa8c398daca7e3f8bd15d4b2e191b8fa7d72547f72e57668630f3430000000000010000e104131a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e8800206af0063f6484fc2fa8e6fe0264faec9dba3f7efaa4f888c9998ea3fe0520e42a56cb0a715d87a7ad6434f43fd50065329f5230598c84aa372b6a1ed1735aa13e0000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001140ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001033b3d4b0000000000ea30550000000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b5dafd0f0596077e5010e7d7876a42e26a54669cb6ab0f1f073bf87b3d88a3043bc48e1625ffa8c398daca7e3f8bd15d4b2e191b8fa7d72547f72e57668630f3430000000000010000e104131a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e8800206af0063f6484fc2fa8e6fe0264faec9dba3f7efaa4f888c9998ea3fe0520e42a56cb0a715d87a7ad6434f43fd50065329f5230598c84aa372b6a1ed1735aa13e0200d0070000dc06010100201ba2b33dda3b5437782a9c6370a15fc8f11fa60dbea2c8f918f838e0e4c1842114085668fb0e76c2884e12c516aef88770c3d61341505f165c0940a6b50f141b0100af3578daed3c0b8c5c5775f7f33eb3f366ece7609261ed36771e4b3aa64ed90467bd0d69e3b725fe902f69a0f4c77abc3bf6ceecd7b3b3c6aea8c734566a3e9568a12509550b286d4868a81410a2202a272512d0564d2141b82a2dad2a15416953552a1451d2f3b9f7cd9bd9dde03049402a9b78e7befbee39f7def33fe7ded9f09fa2376af1aa0bdebb04fc48fc25be36fe3af8bdef656f7bf8d17c87f8e037aebefa2fefc975fd393cd45717b147de2d5f725888c3aadb158775177f7ba7e147760f0b79fab0d73d7d1abafc2efe409fe60f95fd3e6ddf89c3018251bf3c0df84e3b4c80f6340d94d023bb841861e10560a769795497401899821ef5943fa61b4b27a2d923d3479b4bb3d3cd893d42634fa9b1bcda5c9eaeafae36da1d21b12b9e596bb71b4b9de97663a6d13cd1680b0fbbfdfa91651822b05de6f1d3ab73f5abaf99108a70f7faaee29edca86baeba9afb62dbd76eae341667af9a18e7ee208f69641ad633b7d069be52f8f8ecf55006795c2303482258f032ac777abe714a04d863561b9de9230bcb33f33373f5e6d2f44abd5d5f6c741aed5568cecc376679c7c162637166e5940809e6d8f78229e0b04b11f54a7b796579b5318b8dd9b51918234688aa8e849de66283c9b71dd1d6673a40d0dc684255586937973aabd30bbc9a4b1c8972bb291256e0de6a67b9dd20f645d4d56e1c5f6b424f7dad33274ad8b58517d63cd15c681c83d596b1f345d8d96eac2eafb5671ad30bcdc56667556cc1372fd9781fd38d93622b41aeb41bb4ec7aa7317db451efacb51b2226aaf1b2f9617b73d5bd9d76c367c53666393c2f2f4dcfd63bf5e9d5e6af35c425d40d7867a773ef9818dbf202393db33cdb102fc2fe226c1e49885b273e95a1636d651697857ddb7b949c83b54bbdff06f1e26db1d816c771292ea8f8d2822a5c26652c2bfc5390f643560af8290ad094ee9f2ac882829f82e7cb15592efb5a0a195caabb323d735e445d91fef363d9473822fdfacacac229f1b2914ba44865547addeb7fe1177fe9977ff58dd3b38da3c50fbd5ddee089b8167d590b23e22be331238c7cadb76feacc99ff79e281b3f7fcfdbd5da3e019bbe357f9d0fdd0177feb77dffbc0eb7abdd7b9de0ffdede744affb67b0fbcc571ffec6f92fbc3d87e367ede88f7fe23fefe8f55e0fbddffae3273effc1f77fe1911c8e7d84e3cc139ffec085a95e6fcabd67be7977bef7d5dcfbe16fffc3d7eecbcd7703777fec9b5fcc0fde8fbd1fffeffbde736fbef7008d3dffae6ff78d3d48bdbff7d75f7f22df7b13e3fdbb3f79ef173f919bee16ea7efce18f7cf29eab7bbdb7fa53ef7ce0c2852fbfe39ebec1b7f946f056ce7fe2ee27c5eddebe949e2f7ce123dff88dff10b189067ffcdc70c7a7be3d0382b7f42348457c55d496baab60d2b248c556e84a454dbd039ed3f844225b899a8027ee3dbb2fd146b4d2adad74e5782226a00300551a778cb811c1a12d5b38de4868546504afe53e91760fe0dbf49de7452c23a32325a20929bb2f8539e6137833a14a000c33946a4af4d09fd987bd384d2aae1788377aa5545d589a34624755aa7d1af0c75724a22c5351e535a689baa12c8dda2644494491115180e2fb13910f3a2fecef222e56ecd5e7d2e8165ec857c47c22c78070b0f42f09d844819a31b4bcac85af45fc8a517a34b286af60c5f3f116e8f98a688d89e80305582192b30618e09797a8f9347c0defff11d83f7556556414c014e2ada38676eea505a2b587bdadaa7628005a6f0cad532f07ed65d0a5a1a0e3a1a0b70f055d190a7ae750d06628e8b1a1a06b4341ef1e0a7a7c28e83d43414f0e057ddd50d0e7453fb8dc0c5ce5c05506fe2880cbef0d2e07c0115844df965a76d569b23be3f38926b38373c5adb83025aa5e1a57d1a02968fb60e2f08551ad6aa0d0de02ce436561fca9c25dc633c155429c4dbca9c97367ab3ebcebc2ba8c07efaa5e89ed6f2af7d3da1e60eb0b907b35982607bb570b9c0eed7dab2a70769c3522539ea8d480e9663431a0e94daf011ee7d39df4642b1e8135165abb34401a8d1f1e4ee4edc5c881e603ab0fa206f6114cff7b202c817cc0c3ed3f2578ff1a1410fd00b4a6c02e57e0a3bb57c7308d007489874bd6849068e0c116d1bbddfb6f1ffdf7abc00508f42207697d0011bf32017a8f1bcd1b3fff28bb1d03bc1bc7f7b496780fd3c78bd56b69d8dbfe02878160c4bb12818b888126b556e2631bf6012b4c02d7aeb492d0b68d46b4c0427c42cc46814f480af8e199c27c3c0e84c27e0082bde0a8809f63f71c22d1262db65d7a9c774e636a203373f661421de609043b0e3ba4d09e50b3d00407445c8caf19653c853c8d2c212dd6f8d2c49f507b88943032be03593a751ac82adf0cbf7efdf53b600d48334193665c40fa01e06ee282aea99d89c20f732bc02b7c13c307732b25506598ab204f15d8c0ce1272029a76bdb41d0d362c9e8810d1e1aa7090e286323aee97473c5325f16f288bdebc205707500daa02506a8c57e65ac876501b4321050a83421c0a70000b044a3261aae2272e7627e187099f22df7d36d0234e2f311e505558f618cf297005a0bce06690bb3e29034ceb83f8d73030d80f4107a804ae02175652107bc0f37e5c2374e2c2029238fe0f5407561957133fedb2edf82f1453248f9fbec53b54c6467c45354c65b580bd405d8e8ce693700cc65741a724488e1f5747596803165a2ba301127edc04406bdb0102ec5a356e295c7f48a15b7ae1d3a425810959b8420c433cc53b4c2fef1b84f25f1d013c60328a403e30a6c64b0d8081ed88c09cf8a4d05595b239299111a351ad6a99b6efb31929a1158b4c99ac584456ac04efc08af926422b16b196face8a7dec315a8132251432e560d98af9188cb6c86e46382d7000ad98975931df59313b3d5a2d408153f60c19a9252c0335a81ae15c11528da78c4c115f18ec2922343cd4f88184dae4d4bc88769bbae29ee64b503b90be604219fc40bd02f468b7e0cd4e276b3b139f2c0e880daa968f2f63f88832d532f014a06aa17c65aa3542f359626b1056d02bc058403d082108266525f6300aecf75907287e354174b7d20acc33698101eb5c050b3146961f6daa60367c8a8ca5da172b320d6c41bf4e9d46b21ff0d80ed2af808d6180c610e31de04b46258cbde039ee3d03213da03d3d608bc49a425385aca30978c63f6079d4e96d2d722368de6a14bc7b6896d1eed820db235ea3ff8575a18584ddec994209a8c5096115d60c0a30833e9a413f33832040681f3eaf7b7e1b2803a6815c3ced24d1d789cb38a6a7476fca9cbb4e68b486533568296a8d434b526b125a08ae69dc8bb0753fd882c2896bc5a5a4eb31b45e4cad0ab4b623100cb85684d487e3826c9c9f8df370093cffe45d38f55d9c159e39ffb4b8f32c74546cc757aebf93c2047a7aeaf23bcfe2cbc2397cfcd6567c55c1f6774202aa41fbbbfa4e5af6d9b36759f3609af8799ea6420442a26da31612f2126a21f9e2be344bcea797b3213df7681684a134824d30b920cc901028e228c462f76ae977ad49c6f7f80ba8379f5616811d603c82f4434f3ef8246a61fa2036aaa11b0b4246c3bcf489079f7c391848d06eb0379d2404b31c1cda9184b81cb0e0826231b0a895857817864692bc01ba009451f41a958504f23f89ea2950d361d524f79885063c08c15b14e381f10d6c6ec9cb0dd9f9145ae068aa52634e0e6ec8c3592068e259242b04ca27bc5e81d82ed3378c2ea19ba6c6e7398a21c18f86c623a749535a92863425ec08025c11ef86b721477b3eaa9dc0d57a180db103060c6030604521ae284448705ace3d4b343f12cd0f6c0f67a2800c3b3de88c1e57da739628267d4b7143e4dd612a70610a4b0ebc6a2407a7e3893f9ffa6b0f5503f23a12e27cf089e139f48fb7e36e1451c2f2dc770b54d640a049c0149aac2a11f71931a56f269830edee2f2b8b9ab4b1d48a5f3b4a26907041f0e85b6a12fd7c4b4d20236cca47390119896f17118738e8d9c1d3df5ca698d084f3f1cf59408aa04c782bbd014b8ef21c71f0e5f1072e00b12395404fe39f1f25bf0816ec4fb5420bd6b35f68bce3cb9e633326323326323326f2664cb01913991913991913ffffcc18f8a31de9a72073dc09bcfae9f493d4620315fd7ebfcbe10a95b0bc52c82b7c645e69cb2b69a750d4625e493b19659a9657d0ba1f8c17f34aa20b265e618b792591991ef20afb98576e9c9f8df35c6ea191887a9088ba8f88ba9f883a47449d23a2ce88a87bbca269e2e7799a0a118879852de615b6985710adc42fa59805b873ff8f02821fb68040c53f4641c0971ee13c8119f567527ace8bf4923a085f7f3cf1cab6e650c08a0b3901b2b15c6748cf7887c81d5d51559c85792e0b0324f41c5f3e6a115860180239958c7af912e6259cb1730286de9662592f3d793c2d1cc8e7563a1bcb26fbd552c3ca71d9bc5c97045fe4d2220cde7f846403249f552c13e37d32c11281a2f02c65c01698c6f803733be86f6195a5666b5a842b9f6d63b457c364aca6c6b05e487511c77d12122c378e5194a20e3c13dc6508271d9c7c06380b70e900002d3ca5d0339365ca230bad786a946b2e8584ca29b4bf1257556c51ef69692b7ab6f409b9b7c6a857d3f910c5ca876819773ed6571fbd525020c44ba6c01143a5a7c57120d4d3f278a23a0f9d45d6a4610bb2d0a08a46ed8c3c5eb64112c57c3ec77c0a8225725718176130ec22260f036dfce081cc42084b6f2e73d59579e4452ea60fe6916af3897f6b8e708c07591d40ba9c2513c6b715ddbb555f1651e0c0dc4bf4bc918728bc047a5c2b844b4260bb9a0bc95d88fa6db548bbdc03f7848947f7a6b24c9f869f10059d48092f55fa5de8d29c6f28cc3734161220dfd024b8da0aafd1906c70111bf305a01da40455dd5b8b8d68dd1a3008ef654012269aa7fa0f4c7110c51fa9455ba7203ee250bfc0f54f8cf83d0ac35d44bfd566070f2ba5413440cfcec8e754d1eee08fdbaca24da837b0e41edc50cdee60b1ff8c185030c28372bf8fa127e1e9712a9d4ca2e093025095077b394742dd72855e2e31e85dfab6c4e712b5dcab51f7b9868da5ef9a2d77eed20719ebd5ac4d93396dbace69d31989ea74d390e60d36fee479da3874fe8d541e33e007edfc725e6fc0e5817e67e6088b6e81d1570a482b0de62698548b0371c539c407156cc87339cc661baad80d55bedf0d552cf0f7da906fdd78b27e579057fb6e64ec46c603830ab94115479fca26210156d602a6119d19c4d5027e54aa2344aa1153c0d243fc12b2deb0a3f76b19f5fb3834cb44a9ac9aee5baa60b5d91ba8347b6364167cab76a0e2dbf923e60320d09f0aeb4fc1c536b46d1d1f1aa515b11789f74e91161a3c7f001f04662c1eb55ec5907c33d631cafbb95f2441aedeef81750fb0de1fd01ab1a000043fdcc26a0c92bf9514f0ea4017cbed5ebad04a4610431131172de1575a4944f6d51439e3f7d28319fb5a5ca72c3106cd25c9832d534a55273df79840c5df265144d22e2abd0fc259a41388c88c505a1e99c814e915aa728187f1a2a9ea4a67629acb235ece77fe95a672eb482e87206fa3e920900e00f9546b2327aa23d414940936e7ec55c0559213f5c989fae844b1c614a2346bac61ac73a261ae709204985868f6a31a6bb6af61078a050a3cbaba992be830a1df01ba9bd0567812ed18a291a02319433432a4881344c890080f32a1131882f73dc07d45fbad8f3cd8b2ef00dec77765c6a0b8b80e0c290f32c4674a07b0afc852bb48e5352ceb47f40aa93de21852a03a136cad80a4023d8a9808b88ed0958204974e349f677161683b6931297d7c2389084230b6ac9cf887812e023775af64d58b0934c7041e12d9850558074face678f6036671ad42cb2995e052bf2d6126de60f4909d2b59ffed58093211a698875105130287eb51ff49a2fc79e098bf86e1041eef50b54ea7de5a821214423cc1fe19855063b5cf737834b6fd0e84179aac02ca011a22102c9488110cfc7abba9b436df17eea5eae54210a25091b71060452d30c5f96ac47a00f60d621889c211303b8bd88162c72736928a8c1cdd48e8c5131b61e529274d12456f0b970f25cae65626ef16124a5b06ddca62bb25ab8a765002617bd2f620b1e6dce8c09479142322dc68117c584562cd04ac15ed3487a41445954bda864978290964b88c615581c32a8fc3aa112e95c2042c9c01dbbdc0d9adb0dfeee17a133e3aa50b0a64f7b6b2dd1339bb271d3c995adfa959c1da3d7f50cd34135c56a9b84b1bda6203c1ad7cc44b75dcd06aa329b362947125657c632b909f93140ff2fe55a67a18796bab1d83b19b57f5d855bb436fbe2d35c1a12ad6a909877456d3cf520f8d6ffaaca6cc5b4d327099d5c403b75eeae1a1d524e78f02aaa9eccc5693b206fffef870f4564981dae059f1f311d9daa0144ccfcdceb142fba7dcb1dd26d7ce6e1c4c61149f875cdcb5b38da03114b9b86b67cf0e3a1e0a7afb50d095a1a0770e056d86821e1b0aba3614f4eea1a0c78782de3314f4e450d0d70d05bdeedad966e01779ed6c330ddfe8dad9bb7f588aa090be90052387f00ecff72862b2077d4f6d624c375c8e3fb01c1f97e3b3319da254c95d7549e32adfb0cba290eca2195e2f20bcfd975c7cbcac125ad3ebf319329ee361a483f23b622fb71429727d9c2fb7f01215df2e29e2e596c04474b925a0cb2d454c2020cb33015e6ee10b4198faf65d6e19314524e4888375cb1f41333982fbc269d75d6e51ee728b7257f420788287c12b7a459b47e244015282e7e38c9503edfc65354bb4812b6bda5e59ab708bafac51910410845c21f917a049814b243e5f23937bf51bb83a725be6d3e2563c995dc1fa8cd69e3b51f9a191843e1120defb96f7619ef7853cef43e67d21c7fbf06278ef9b1079ef3b58b7609f2a0896f7e145f13edc80f761c67b9f79cff30dcf7b7b7df5da8c934f4aadfb0fef39d5d41cad419c37b9f8101f830bbab3c05f19303e1eb0fbf680dddd23e07b8a367cada9f12478881282cd61dcc5c3c01dcc2b4ae928c0854e886ebff3888b6ed9500ab4b304ea818bc04a85cbed62caedb6d2e93c7f7fe0bb5cf0d6039be36f03d0e5034ef62813d2f7e3c534102f5824c8d8ed90bc841dae73b7af155b739749c4ba0b2c1e965f140ab5cc59746913c0c0decda5109ec91b10917238c38d71fa034120271b3e4695778cbafb0a01de2b6198529e14d19725152d546eff5c8f30f21a1573fec7bbf670d7dee6bbd61bed5ab30f5cbf6bddbfebd8e5731e17721c46bd314639e094ed9ee3378c0e30f93216084aa55834aa78cb63d3fe134aba9c860ac474ed234d5a894d1d6bad6b949882d695622c95c77750155ea0ec8a9e58f085127733a6a66a341cd25d7902e5fcf88e848aeb78aa2f68d6e81eddbb48bd5e0a51bd5e4029747218b21c4a5b14ba468df399c3334ebfe562a6dfb2f9f44edb43b40dde7a950f41a741e53ffa68a6f22106917e5fc6e465d7f8d72bcb40384613876826424e8607cdc42c64863d59a1c00ccb2868b2f038c6cbc570ebf7abd8930d6c9642404e57d32acdf9824cf2a07c01660101aff607c69ba0d203a8ec6533c884e25f198dfe77bd596285806c1fa60245d2a8480f556de540bf4076caaec0c715c0afe349b083eaef549e202766821d54d2b17319ff960de7dae0f431679515fd3f4af6832d0dcd01a91ab00e2fd47dd81e791bfad205872b549fdd9efbf2852af1a997d7eef1d6551436ce76f84ae146b6d58beba3fda69a8e6ce9d631577fec999aa09bf264150ff22188c0e2944775405745aeb4e835bbef7c71cae3aa93aa0a7be21d71a1879221ba9748e76b92528fbdae4e17f365483c4681be12e52aef7bcc467c747cf29b5c9bf7d6b9b917b2366f0fb843b4e8eb6bf347ece1765f6d1eb396c905accd5baafa48556d2ff32701e1cb95fcf03598b301aada1aab8695155c309495cdfd5cd9dcb1cee87866b44f64828d52d400e9bb87d8b82e4bc51352c4d86f53a3f7fbb2d45f525f5f549f5cec15d5c7b9a8aeb8a84e211d45ff2a2b48abac20adb282b4e28234b7fa4bee931b94dc73a576e20c95daffe8773e3b766b59a6f7c167aed28e2374fadb9fbdef123cb747fec8ce86757689d23cb9d0abad031f6d6d1d39daabad7f5f9b42cab8d6645fe53dbb00edaaeff4ed9a8d8ad1f4151557959754952743deabcae3418d2dc303d222be26b92bf59de8905bf6b3339d775bc9a3ea7189cbea11ddaf85416f6ebd428a5781db464f01c8b900ed56c791a75ba4bd5d4bcbb2c967ee78c973c74b24bbb672aef86c490c6a80e4fd20767b7937ca7d6582a5d35d74f847feda8476c7adc3d98a70bdadd06c2b34db8a70d056a05de0fb1f7c99b9d5f327e18141150cf98b3e035e2b1c74cbf64b1ff06879566b51c97c904c7c595d58bb3ace5fe9c03331d8139fc5d0c5264e2b4576e53cee3d17f8608d9f4b74bb04268a8f2195c7d906dc44f77576090bb1d90c6260063130033d3fb7c84e4ad92574ca1e29597456667be8dc7b87ce3d3b74ee79373eefe6b319bebb0fb8c7f6aa31a3507bed552d11fdabc70710e745cea1a3462b32bbfcbc4509694fd6f80b59a40a052a596401b03ab08163f7dda58c81c8cdd61efa44243bea9d6cd195e4752242ae9788273311a138a39fecd4d52f28d4d52f2bf65a8e1517c50e2517c2ec7ebeb60ba876e563de8df078ebf0b0f1c4af39262a9e1b7d76342389a0afae3a111beba35e5eca72d453eba9a7d653af276eeefb1f0371d0792ae6bc0fbf2593bbe48ca4ae9030e2b7644998e99a204b5c0dcfca21e44bf43c5fee40eccc1de5ce7d576e2d2b5bc42bde482618bf3a836200c46b733c83be0cff144400de906274fe86430003ecb72cc0fce35d109fac2702e35776e8eb6d74b5cd435df0ca744b80bd1187c6907a1fa7c818298733611cee8e8dc5848dd75dfc0cefe297dba3ddccd8e5f53623dc73829f6fd3483e426672c61c32d386b73be7636cba09b1ed4f8263fabaafe92f6c44a78ed69b0b8d59d35936f58585e5997aa76156eac71aab626da97172a531d381978d767bb96d9a4be668f3646376fac8a94e63d5cc2c2fad76da6b339de5b6e8cc35ccf2120fe33f776366ea4b4bcb1d73a401ad059c61b6d9066c0ba784fb49dffa88882e78f609ff3c0ee06bd4174dbdd3692cae7478556f6a376949ab1d83b33496664551d83fc3033861a51d93fd359e6b8d58692f77966796178c1bd35c35b890de5fece13f80a5e09f7e76f30a5cab0fff02f8b77ca405dbc101ab0c00c3db7520c634b6794ea0d8e2da42a739dd5c9a6d9c144c1ffc9b40cda563d978612935032f6046c6bb8ab09dfa9105e8386aeaf07eaed1469277dab091f5932f2ecf368f9eda645e3b811d735113f05f1d6a3b2ececcd5978e0135dacdc57afb94996f9c326f9a6b2c5994b89bfa9245bc294171dffdf43cd6e80811022d0bf06f04fe15e15f24f04fb108d15c3a515f68ce9a13f576b3be847bc2ad3c1ba1045b1b795f4d00d7ff019e55743300d007000082010101002071c6cbdee3f4d6824fb9876d6362d085242ac20ad2e5cff92667c7f9a21e805874361f0f0af17fbbb704e35533a3678c5f59434140ff314085ad604beb1fb0640100e60778da8d563b8f1c4510eedd9d7ddcae7d3a0ecc710e088c482c197c6bb33a99e408480808784487197aa76b775a3bd33374f7ecde424c6048909c1909590881838bce897510589b22216170c023003290f80f54cfccceebb8e53a984755757557d5575f77fb8fdebb0df2f2cfd66d82a3661ee4efab6f9bd703e7685112dcfba7dfbfbdb994dcda5c8740f1e0c60d3ae42feebcd0af6d0dbdc099d88a8f0517639b46da0d24d7f34b532a3915da3e456f4faf6e77d089ed52e5927a3398099096a03e5846d2735c70262af2fb2f0d3ad4d17c4a3590dafa08a88e24d88c8f41e9a2d55ae69a586bda95a0dcc063ad880b7dad6f4d60aecee1c39e011fbb7aff263a75824868b51d82f4b9c2a084edc114bccca439a35cabf3e699c92e9e1e0ea99f61d90bf17cc7a55cd8219518ae06a9c8134ffaf4204d95006d478a8e217632b87e515339065dd5daa1a3d365b6cd642da95026531847d9c5b5feb343aa7002c895561bb96f0f6046e7a9fc3927101a0eb43d926032afe2c415762222ffaca60c446a5a88d809a3d246ca1167da5511575d6cfb98e05506cf543d787c049afb59ca188c404a60687460c341c8258ded665cb060965a5da87a61e065797bda28b9f0b8003b552bfec17281ad935a06a17663f5ce204e4f0eafa2aae750e180172f45eaebc9df128d1b5538b7ccfe392bb64a17a722ee8c39a9b7d346887baf9bcf4efe73ec927a037fba6134f4b863e3672b91a79beae00e26b147abe4d1720206c9979e87c9574fc2fb1197e0c3725981704b26e174476293072919648f8421f22e6fc5ac00b9a01da05e0612fb5081600876cedaf1e6fabb1d946853c9e670ae419d48121210ba4bd7ac2661eb148620f582e5c9bc97d2b319ca80450e6e2aa7a9faf94c98459987731ab19ec3e42d0991ad64c4b6b13415a9592319f8b1ff96028dac5b297b03454966ba46ef711f89af52c835242b3bb669c6b4d4354d9dc4980a4c8b15056df465aa5f71d49afa06094d9398ddb5a93f4502c4ac25ff315c92ad6015754c918ad45ac9c77fb3a75927947c5a09aacd956dc489e34e6c143074d65198241679f0d4c9a2ecdfec46228372e37fa1dc8d4246d356b256b69209618977cbd8e7a5ee158e1852efc47f0a9c9428ca40dac083f8f2677828e7a722f9f6d6e5573ffaea95122f90bdef7eb977f8c56bc55ec77165d2f8fa93bc57c9dee7772eb107778a0d88e3f7471f3efe32eba74fdf1afc0aecf0b88c3c1c77c13f3cce50b6bc3e2c2146c8f7af1fbb478b22a470ec3dfff1d1228306210f1fbdf3e6fd45a1d838defb66fffe222b2b8edd1f509097d004f7f0af3f7f2ad62a0ed87be371b122e6267397fef8db4e830fae1392df37f0d673860b4a6dd5694ffe059b3958df0001 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304003,"value_ex":101997,"consumed":7929},"cpu_usage":{"last_ordinal":1262304003,"value_ex":279534,"consumed":4101},"ram_usage":199629} +DMLOG APPLIED_TRANSACTION 4 5ade57480d2e64fb49dd5d8303b08ecff6499745f854b8e70dff5f00cc1c060b04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e50100d00700008301000000000000000018040000000000000001010000010000000000ea30552deb8b0eef2f2bfd027d20727a96e4b30eb6ccdc27488670d57bf488395c48fc1b000000000000001b00000000000000010000000000ea30551b0000000000000002020000000000ea30550000000000ea305500000000b863b2c2010000000000ea305500000000a8ed323293120000000000ea305589120e656f73696f3a3a6162692f312e320117626c6f636b5f7369676e696e675f617574686f726974792276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f763019086162695f686173680002056f776e6572046e616d6504686173680b636865636b73756d32353608616374697661746500010e666561747572655f6469676573740b636865636b73756d32353609617574686f726974790004097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d086163636f756e7473197065726d697373696f6e5f6c6576656c5f7765696768745b5d0577616974730d776169745f7765696768745b5d1a626c6f636b5f7369676e696e675f617574686f726974795f76300002097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d15626c6f636b636861696e5f706172616d65746572730011136d61785f626c6f636b5f6e65745f75736167650675696e7436341a7461726765745f626c6f636b5f6e65745f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6e65745f75736167650675696e7433321e626173655f7065725f7472616e73616374696f6e5f6e65745f75736167650675696e743332106e65745f75736167655f6c65657761790675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f6e756d0675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f64656e0675696e743332136d61785f626c6f636b5f6370755f75736167650675696e7433321a7461726765745f626c6f636b5f6370755f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6370755f75736167650675696e743332196d696e5f7472616e73616374696f6e5f6370755f75736167650675696e743332186d61785f7472616e73616374696f6e5f6c69666574696d650675696e7433321e64656665727265645f7472785f65787069726174696f6e5f77696e646f770675696e743332156d61785f7472616e73616374696f6e5f64656c61790675696e743332166d61785f696e6c696e655f616374696f6e5f73697a650675696e743332176d61785f696e6c696e655f616374696f6e5f64657074680675696e743136136d61785f617574686f726974795f64657074680675696e7431360b63616e63656c64656c617900020e63616e63656c696e675f61757468107065726d697373696f6e5f6c6576656c067472785f69640b636865636b73756d3235360a64656c657465617574680002076163636f756e74046e616d650a7065726d697373696f6e046e616d650a6b65795f7765696768740002036b65790a7075626c69635f6b6579067765696768740675696e743136086c696e6b617574680004076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650b726571756972656d656e74046e616d650a6e65776163636f756e7400040763726561746f72046e616d65046e616d65046e616d65056f776e657209617574686f726974790661637469766509617574686f72697479076f6e6572726f7200020973656e6465725f69640775696e743132380873656e745f747278056279746573107065726d697373696f6e5f6c6576656c0002056163746f72046e616d650a7065726d697373696f6e046e616d65177065726d697373696f6e5f6c6576656c5f77656967687400020a7065726d697373696f6e107065726d697373696f6e5f6c6576656c067765696768740675696e7431361270726f64756365725f617574686f7269747900020d70726f64756365725f6e616d65046e616d6509617574686f7269747917626c6f636b5f7369676e696e675f617574686f726974790c72657161637469766174656400010e666561747572655f6469676573740b636865636b73756d323536077265716175746800010466726f6d046e616d65067365746162690002076163636f756e74046e616d65036162690562797465730a736574616c696d6974730004076163636f756e74046e616d650972616d5f627974657305696e7436340a6e65745f77656967687405696e7436340a6370755f77656967687405696e74363407736574636f64650004076163636f756e74046e616d6506766d747970650575696e743809766d76657273696f6e0575696e743804636f646505627974657309736574706172616d73000106706172616d7315626c6f636b636861696e5f706172616d657465727307736574707269760002076163636f756e74046e616d650769735f707269760575696e74380873657470726f64730001087363686564756c651470726f64756365725f617574686f726974795b5d0a756e6c696e6b617574680003076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650a757064617465617574680004076163636f756e74046e616d650a7065726d697373696f6e046e616d6506706172656e74046e616d65046175746809617574686f726974790b776169745f776569676874000208776169745f7365630675696e743332067765696768740675696e743136100000002a9bed32320861637469766174650000bc892a4585a6410b63616e63656c64656c6179000040cbdaa8aca24a0a64656c65746561757468000000002d6b03a78b086c696e6b617574680000409e9a2264b89a0a6e65776163636f756e7400000000e0d27bd5a4076f6e6572726f7200905436db6564acba0c72657161637469766174656400000000a0656dacba07726571617574680000000000b863b2c206736574616269000000ce4eba68b2c20a736574616c696d6974730000000040258ab2c207736574636f6465000000c0d25c53b3c209736574706172616d730000000060bb5bb3c207736574707269760000000038d15bb3c20873657470726f6473000040cbdac0e9e2d40a756e6c696e6b61757468000040cbdaa86c52d50a757064617465617574680001000000a061d3dc31036936340000086162695f68617368000000012276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f7630011a626c6f636b5f7369676e696e675f617574686f726974795f763000000000000000000000005ade57480d2e64fb49dd5d8303b08ecff6499745f854b8e70dff5f00cc1c060b04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e5010000000000ea3055890000000000000000000000000000 +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":80800000,"consumed":9696},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":368326389,"consumed":44101},"pending_net_usage":7928,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":146193333,"consumed":8009},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":399423669,"consumed":4466},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} +DMLOG ACCEPTED_BLOCK 4 04000000040000000300000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000300000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7192d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b5a5902476311cae3e60a34f4b68b4336275d05d6835128c04ba783367af61f050300000000000000010000000000ea305504000000010000000000ea305503000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e5033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc002011cfaa913847cc0153220aaca619114879a97d55942af073d83a71fd044ede7257cda33f044c154d10a137e48e9862e00bf114268cc46b3eef3a622c7fd6c3a20000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001150ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fccad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc002011cfaa913847cc0153220aaca619114879a97d55942af073d83a71fd044ede7257cda33f044c154d10a137e48e9862e00bf114268cc46b3eef3a622c7fd6c3a20200d0070000dc060101001f00e74c5607ebe92350dc791bb2cb65c8ceb52fe6623104137f710805b93a84e23a3530fea5cea3743b77736669d4962f0be8dbe1bede210eb1c2460924b505a60100af3578daed3c0b8c5c5775f7f33eb3f366ece7609261ed36771e4b3aa64ed90467bd3569e3b725fe902f69a0f4c77abc3bf6ceecd7b3b3c6aea8c734566a3e95684b4b12aa1650da90d05029204441544e4a24a0544d2141a42a2dad2a15416953552a1451d2f3b9f7cd9bd9dde03049402a9b78e7befbee39f7def33fe7ded9f09fa2376a717edfe73e21e047e22ff1b5f1d7c1effd2f7bdb438fe43bc407be71f5d57f7577aeeb2fe0a1beba883df22ef99223421c51ddae38a2bbf8db3b033fb27b44c83347bcee9933d0e577f107fa347fa8ecf719fb4e1c09108cfae519c077c66102b46768a0841ed925c4080b2f003b4dcba3ba04c2c814f4a8a7fc31dd583a19cd1e9d3ed65c9a9d6e4eec111a7b4a8de5d5e6f2747d75b5d1ee08895df1cc5abbdd58ea4cb71b338de6c9465b78d8edd78f2ec31081ed328f9f5e9dab5f7dcd845084bbd77715f7e4465d73d5d5dc17dbbe7673a5b1387bd5c4387707794c23d3b09eb9854ef395c2c767af8732c8e31a194012c1829761bdd3f38dd322c01eb3dae84c1f5d589e999f99ab3797a657eaedfa62a3d368af427366be31cb3b0e161b8b332ba7454830c7bf174c01875d8aa857dacb2bcbab8d596cccaecdc0183142547524ec34171b4cbeed88b63ed30182e64613aac24abbb9d4599d5ee0d55ce24894db4d91b002f7563bcbed06b12fa2ae76e3c45a137aea6b9d3951c2ae2dbcb0e6c9e642e338acb68c9d2fc2ce76637579ad3dd3985e682e363bab620bbe79c9c6fb986e9c125b0972a5dda065d73b8de9638d7a67addd1031518d97cd0fdb9babeeedb41b3e2bb631cbe17979697ab6dea94faf367fad212ea16ec03b3b9d7bc7c4d89617c8e999e5d9867811f61761f34842dc3af1a90c1d6b2bb3b82cecdbdea3e41cac5dea03d78b176f8bc5b6388e4b7141c5971654e132296359e19f82b41fb252c04f5180a674ff54411614fc143c5faec872d9d752c8e052dd95e9d90b22ea8af49f1fcd3ec211e9d75756164e8b978d5c22452aa3d2eb5eff0bbff84bbffcab6f9c9e6d1c2b7ef0edf27a4fc4b5e8cb5a18115f198f1961e46bbdfd5367cffecfe3f79fbbfbefefe91a05cfd81dbfca87ee07bff85bbff79efb5fd7ebbdd6f57ef06f3f2b7add3f83dd67bffad0372e7ce1ed391c3f6b477fece3ff797baff73ae8fdd69f3cfef90fbcef0b0fe770ec271c671fffd4fb9f9ceaf5a6dc7bf69b77e57b5fcdbd1ffaf63f7ceddedc7cd773f747bff9c5fce003d8fbb1ffbef7ddf7e47b0fd2d80bbffbedbeb187a8f7f7fffaeb8fe77b6f64bc7ff7a7eff9e2c773d3dd4cdd8f3df4e14fdc7d75aff7167fea9df73ff9e497df7177dfe05b7d23782b173e7ed713e2366f7f4acf4f7ee1c3dff88dff10b189067ffcdc70c7a7be3d0382b7f42348457c55d496baab60d2b248c556e84a454dbd039ed3f864225b899a8027ee3db73fd146b4d2adad74e5442226a00300551a778cb801c1a12d5b38de4868546504afe57e91760fe2dbf49d17442c23a32325a20929bb2f8539e6137833a14a000c33946a4af4d09fdd8fbd384d2aae1388377aa5545d589a34624755aafd1af0c75724a22c5351e535a689babe2c8dda2644494491115180e2fb13910f3a2fecef222e56ecd5e7d3e8665ec857c47c22c78070b0f42f09d844819a31b4bcac85af45fc8a517a34b286af60c5f3f116e8f98a688d89e8fd05582192b30618e09797a8f9347c0defff61d83f7556556414c014e2ada38676eea505a2b587bdadaa7628005a6f0cad532f07ed65d0a5a1a0e3a1a0b70f055d190a7ae750d06628e8b1a1a06b4341ef1e0a7a7c28e83d43414f0e057ded50d017443fb8dc0c5ce5c05506fe0880cbef0d2e07c0115844df965a76d519b23be3f38926b38373c5adb83025aa5e1a57d1a02968fb60e2f08551ad6aa0d0de02cec36561fca9c29dc633c155429c4bbca9c9f3e7aa3ebcebc2ba8c07efaa5e89ed6f2a0fd0daee67eb0b907b35982607bb570b9c0eed7dab2a70769c3522539ea8d480e9663431a0e94daf011ee7d39df4542b1e8135165abb34401a8d1f1e4ee4edc5c881e603ab0fa206f6114cffbb212c817cc0c3ed3f2578ff1a1410fd00b4a6c02e57e0a3bb57c7308d007489874bd6849068e0c116d1bbddf36f1ff9f7abc00508f42287687d0011bf32017a8f1bcd1bbff008bb1d03bc1bc7f7b496780fd3c78bd56b69d8dbfe12878160c4bb12818b888126b556e2631bf6012b4c02d7aeb492d0b68d46b4c0427c42cc46814f480af8e199c27c3c0e84c27e0082bde0a8809f63f71c22d1262db65d7a9c774e636a203373f661421de109043b0e3ba4d09e50b3d00407445c8caf19653c853c8d2c212dd6f8d2c49f507b88943032be1d593a7506c82adf0cbf7efdf53b600d48334193665c40fa01e06ee282aea99d89c20f730bc02b7c13c307732b25506598ab204f15d8c0ce1272029a76bdb41d0d362c9e8810d191aa7090e2fa323aee97473c5325f1af2f8bdebc205707510daa02506a8c57e65ac876501b4321050a83421c0a70000b044a3261aae2272e7627e187099f22df7d2ed0234e2f311e505558f618cf297005a0bce06690bb3e29034ceb83f8d7303038004107a804ae02175652107bc0f3015c2374e2c2029238fe0f5407561957133fedb2edf82f1453248f9fbec53b5cc6467c45354c65b580bd405d8e8ce693700cc65741a724488e1f5747596803165a2ba301127edc04406bdb0102ec5a356e295c7f48a15bfae4a7484b0213b270851886788a77985ede3708e5bf3a0278c06414817c604c8d971a0003db118139f149a1ab2a657352222346a35ad5326ddf673352422b16993259b188ac5809de8115f34d84562c622df59d15fbe8a3b402654a2864cac1b215f331186d91dd8c705ae0005a312fb362beb362767ab45a8002a7ec1932524b58066a5035c2b922a41a4f199922be30d853446878a8f10309b5c9a97911ed3675c53dcd97a076207dc18432f8817a05e8d16ec19b9d4ed676263e591c101b542d1f5fc6f01165aa65e02940d542f9ca546b84e6b3c4d620aca05780b1807a1042104cca4aec6114d8efb30e50fc6a82e82ea5159867d20203d6b90a16628c2c3fda54c16cf824194bb53f56641ad8827e9d3a8d643fe0b11da45f011bc3008d21c63bc0978c4a187bc173dc7b06427a407b7ac016893585a60a594713f08c7fc8f2a8d35b5be446d0bcd52878f7d02ca3ddb141b647bc46ff0beb420b09bbd9338512508b13c22aac191460067d34837e66064180d03e7c5ef7fc3650064c03b978da49a2af1597714c4f8fde94397fadd0680da76ad052d41a8796a4d624b4105cd3b81761eb3eb0058593fbc4a5a4eb31b45e4cad0ab4b623100cd82742eac3714136cecfc679b8049e7ff24e9cfa4ece0acf5e785adc710e3a2ab6e32bd7dd4161023d3d75f91de7f065e13c3e7e6b2bbeaa60fb3b2101d5a0fd5d7d072dfbdcb973ac79304dfc3c4f53210221d1b6510b097909b5907c715f9a25e7d3cbd9909e7f240bc2501ac126985c1066480814711462b17bb4f4bbd624e37bfc05d49b4f2b8bc00e301e41fac1271e7802b5307d001bd5d08d0521a3615efaf8034fbc1c0c246837d89b4e1282590e0eef48425c0e587041b11858d4ca42bc0b432349de005d00ca287a8dca4202f99f44f514a8e9b06a927bcc42031e84e02d8af1c0f80636b7e4e586ec7c0a2d703455a931270737e4e12c1034f12c921502e5135eaf406c97e91b4697d04d53e3f31cc590e04743e391d3a4292d49439a12760401ae8877c3db90a33d1fd54ee06a3d8c86d80103063018b0a21057142224382de79e259a1f89e607b687335140869d1e74468f29ed394b1493bea5b821f2ee3015b8308525075e359283d3f1c49f4ffdb507ab01791d09713ef8c4f03cfac7db70378a286179eebb052a6b20d024600a4d569588fb8c98d237134c98760f9495454dda586ac5af1d251348b82078f42d35897ebea526901136e5a39c808cc4b78988431cf4ece0e96f2a534c68c2f9f8e72c20455026bc85de802547798e38f8f2f8031780d8914aa0a7f1cf8f925f040bf6675aa105ebd92f34def165cfb11913991913991913793326d88c89cc8c89cc8c89ff7f660cfcd18ef4939039ee045efd74fa096ab1818afea0dfe570854a585e29e4153e32afb4e595b453286a31afa49d8c324dcb2b68dd07c68b7925d10513afb0c5bc92c84c0f79857dcc2b37cecfc6792eb7d048443d4844dd4744dd4f449d23a2ce11516744d43d5ed134f1f33c4d8508c4bcc216f30a5bcc2b8856e29752cc02dcb9ef4701c10f5b40a0e21fa320e04b0f739ec08cfa73293de7457a491d84af3f9e78655b732860c5859c00d958ae33a467bdc3e48eaea82acec23c978501127a8e2f1fb5082c300c819c4a46bd7c09f312ced83901436f4bb1ac979e3a91160ee6732b9d8d6593fd6aa961e5b86c5eae4b822f72691106ef3f42b20192cf289689f13e9960894051789632600b4c63fc81b91df4b7b0ca52b3352dc295cfb631daab6132565363582fa4ba88e33e0909961bc7284a51079f09ee3284930e4e3e039c05b8740080169e52e899c932e59185563c35ca35974242e514da5f89ab2ab6a8f7b4b4153d5bfa84dc5b63d4abe97c8862e5c3b48c3b1eedab8f5e292810e22553e088a1d2d3e20410ea697922519d07cf216bd2b00559685045a376569e28db2089623e9f633e05c112b92b8c8b30187611938781367ef040662184a53795b9eaca3cf22217d307f348b5f9c4bf254738c683ac0e205dce9209e3db8aee5daa2f8b287060ee257adec8c3145e023df609e19210d8aee6427217a27e5b2dd22ef7c03d61e2d1bdb12cd3a7e12744412752c24b957e17ba34e71b0af30d8d8504c8373409aeb6c26b34241b5cc4c67c016807294155f7d662235ab7060cc27b19908489e6a9fe03531c42f1476ad1d629888f38d42f70fd13237e8fc27017d16fb5d9c1434a69100dd0b3b3f23955b4dbf9e356ab6813ea0d2cb9873654b3db59ec3f2d06148cf0a0dcef67e849787a8c4a279328f8a40054e5c15ece9150b75ca1974b0c7a97be35f1b9442df76ad47dae6163e9bb66cb9dbbf421c67a356bd3644e9bae75da7456a23add38a479838d3f7181360e9d7f2395c70cf8413bbf9cd71b7079a0df9939c2a25b60f49502d24a83b90926d5e2605c710ef101051bf25c0eb3d9862a764395ef7743150bfcbd36e45b379eacdf15e4d5be1b19bb91f1c0a0426e50c5d1a7b249488095b5806944670671b5801f95ea08916ac414b0f410bf84ac37ece87d5a46fd3e0ecd32512aaba6fb962a586df6062acdde189905dfaa1da8f876fe88f90008f4a7c2fa5370b10d6d5bc787476945ec45e2bd53a48506cf1fc00781198b47ad573124df8c758cf27eee174990abf77b60dd03acf707b4462c2800c18fb4b01a83e46f2505bc3ad0c572bb972eb49211c45044cc454bf8955612917d3545cef8bdf450c6be16d7294b8c417349f250cb9452d549cf3f2a50f1b7491491b48b4aef837016e9042232239496472632457a85aa5ce061bc68aabad29998e6f28897f39d9fd3546e1dc9e510e46d341d04d201209f6a6de44475849a8232c1e69cbd0ab84a72a23e39511f9d28d6984294668d358c754e34cc154e9200130bcd7e5463cdf635ec40b1408147573771051d26f43b407713da0a4fa21d433412742463884686147182081912e14126740243f0be07b8afe880f591875af61dc0fbf8aecc181417d78121e54186f84ce900f615596a17a9bc8665fd885e21b5471c430a546782ad159054a047111301d711ba5290e0d289e6f32c2e0c6d272d26a58f6f20114108c6969513ff28d045e0a6ee95ac7a3181e698c04322bbb000ebe089d51ccf7ec02cae556839a5125ceab725ccc41b8c1eb27325ebbf1d2b4126c214f330aa6042e0701dea3f49943f0f1cf3d7309cc0e31daad6e9d45b4b5082428827d83fa3106aacf6790e8fc6b6df81f042935540394043048285123182815f6f3795d6e6fbc2bd54bd5c0842142af21602aca805a6385f8d580fc0be410c235138026667113b50ecf8c446529191a31b09bd786223ac3ce5a449a2e86de1f2a144d9dccae4dd424269cba05b596cb76455d10e4a206c4fda1e24d69c1b1d98328f6244841b2d820fab48ac9980b5a29de69094a2a87249db30092f25810c9731ac2a7058e5715835c2a5529880853360bb1738bb15f6db3d5c6fc247a7744181ecde56b67b2267f7a4832753eb3b352b58bbe70faa996682cb2a157769435b6c20b8958f78a98e1b5a6d3465568c32aea48c6f6c05f2b392e241debfca540f236f6db5633076f3aa1ebb6a77e8cdb7a5263854c53a35e190ce6afa59eaa1f14d9fd59479ab49062eb39a78e0d64b3d3cb49ae4fc514035959dd96a52d6e0df171f89de2a29501b3c2b7e3e225b1b9482e9b9c9395668ff943bb6dbe4dad90d83298ce2f3908bbb76b6113486221777edecd941c743416f1f0aba3214f4cea1a0cd50d0634341d78682de3d14f4f850d07b86829e1c0afadaa1a0d75d3bdb0cfc22af9d6da6e11b5d3b7bd70f4b1114d217b260e410dee1f91e454cf6a0efa94d8ce986cbf10796e3e3727c36a653942ab9ab2e695ce51b765914925d34c3eb0584b7ff928b8f9755426b7a7d3e43c6733c8c74507e47ece5962245ae8ff1e5165ea2e2db2545bcdc1298882eb70474b9a5880904647926c0cb2d7c210853dfbecb2d23a688841c71b06ef923682647705f38edbacb2dca5d6e51ee8a1e044ff0307845af68f3489c28404af07c9cb172a09dbfac66893670654ddb2b6b156ef195352a920082902b24ff0234297089c4e76b6472af7e0357476ecd7c5adc8a27b32b589fd6da73272a3f3492d02702c47bdff23eccf3be90e77dc8bc2fe4781f5e0cef7d1322ef7d07eb16ec5305c1f23ebc28de871bf03ecc78ef33ef79bee1796fafafeecb38f984d4bafff09e534dcdd11ac479938b0ff231b8a03b0bfc9501e3e301bb6f0fd8dd3d02bea768c3d79a1a4f82072921d81cc65d3c0cdcc1bca2948e025ce884e8f63b0fbbe8960da5403b4ba01eb808ac54b8dc2ea6dc6e2b9dcef3f707becb056f3db039fe36005d3ee0648f32217d1f5e4c03f18245828cdd06c94bd8e13a777b9fd89abb4c22d65d60f1b0fca250a865cea24b9b0006f66e2e85f04cde808894c3196e8cd31f080239d9f031aabc7dd4dd5708f05e09c394f2a488be2ca968a172fbe77a8491d7a898f33fdeb587bbf636dfb5de68d79a7de0fa5debfe5dc72e9ff3b890e330ea8d31ca01a76cf71cbf617480c997b140502ac5a251c55b1e9bf69f54d2e5345420a66b1f69d24a6cea586b5da3c414b4ae1463a93cb183aaf0026557f4c4822f94b89b313555a3e190eeca9328e7277624545cc7537d41b34677ebde45eaf55288eaf5024aa193c390e550daa2d0356a9ccf1c9e71fa2d1733fd96cda777da1ea26df0d6ab7c083a0d2aff914732950f3188f4fb32262fbbc6bf5e5906c2319a3844331172323c6826662133ecc90a05665846419385c7315e2e865bbf5fc59e6c60b3140272ba9a5669ce17649207e40b300b0878b53f30de04951e40652f9b412614ffca68f4bfebcd122b0464fb3015289246457ab06a2b07fa05b25376053eae007e9d48821d547fa7f204393113eca0928e9dcbf8376f38d706a78f39abace8ff51b21f6c69680e48d5807578a1ee43f6c8dbd0972e385ca1faecf6dc972f54894fbdbc768fb7aea2b071b6c3570a37b2ad5e5c1fed37d574644bb78eb9fa63cfd404dd9427ab78880f410416a73caa03ba2a72a545afd97de78b531e579d5455d813ef880b3d940cd1bd443a5f93947aec7575ba982f43e2310af495285779efa336e2a3e393dfe4dabcb7cecdbd90b5797bc01da2455f5f9b3f6a0fb7fb6af398b54c2e606dde52d547aa6a7b993f09085faee487afc19c0d50d5d65835acace082a1ac6ceee7cae68e7546c733a37d22136c94a20648df3dc4c675592a9e9022c67e9b1abdcf97a5fe92fafaa2fae462afa83ece4575c545750ae928fa5759415a6505699515a41517a4b9d55f729fdca0e49e2bb51367a8d4fec7bff399b15bca32bd173e7395761ca1d3dffeccbd97e0b93df2477636acb34b94e6c9855e6d1df8686bebc8d15e6dfdfbda1452c6b526fb2aefd90568577da76fd76c548ca6afa8b8aabca4aa3c19f25e551e0f6a6c191e9016f135c95da9ef4487dcb29f9de9bccb4a1e558f4b5c568fe87e2d0c7a73eb1552bc0adc367a0a40ce0568b73a8e3cdd22eded5a5a964d3e73c74b9e3b5e22d9b59573c5674b62500324ef07b1dbcbbb51ee2b132c9deea2c33ff2d726b43b6e1dce5684eb6d85665ba1d9568483b602ed02dfffe0cbccad9e3f090f0eaa60c85ff419f05ae1a05bb65ffa8047cbb35a8b4ae68364e2cbeac2dad571fe4a079e89c19ef82c862e36715a29b22be771efb9c0076bfc5ca2db2530517c1ca93cce36e046baafb34b5888cd66100333888119e8f9b945764aca2ea153f648c9a2b332db43e7de3b74eed9a173cfbbf179379fcdf0dd7dc03db6578d1985da6baf6a89e85f3d3e80b820720e1d355a91d9e5e72d4a487bb2c65fc822552850c9220b80d5c10d1cbbef2e650c446eb6f6d02722d951ef648bae24af131172bd443c998908c519fd64a7ae7e41a1ae7e59b1d772acb8287628b91066f7f3b55d40b52b1ff36e84c75b87878d277ecd3151f1dce8b3a31949047d75d589d8581ff5f25296a39e5a4f3db59e7a3d7173dfff1888832e5031e7bdf82d99dc25672475858411bf254bc24cd70459e26a78560e215fa2e7f972076267ee2877eebb724b59d9225ef10632c1f8d5191403205e9be319f465f8a72002f08614a3f3371c021860bf6501e61fef82f8643d1118bfb2435f6fa3ab6d1eea8257a65b02ec8d383486d4fb0445c648399c09e370776c2c266cbceee2677817bfdc1eed66c62eafb719e19e13fc7c9b46f211329333e6909936bcdd391f63d34d886d7f121cd3d77d4d7f61233a7dacde5c68cc9aceb2a92f2c2ccfd43b0db3523fde58156b4b8d532b8d990ebc6cb4dbcb6dd35c32c79aa71ab3d3474f771aab66667969b5d35e9be92cb74567ae6196977818ffb91b33535f5a5aee98a30d682de00cb3cd36605b382ddc4ffad68745f4a4679ff0cfe300be467dd1d43b9dc6e24a8757f5a6769396b4da31384b6369561485fd333c801356da31d95fe3d967c44a7bb9b33cb3bc60dc98e6aac185f4fe620fff012c05fff4b39b57e05a7df817c0bfe5a32dd80e0e58650018deae0331a6b1cd7302c516d7163acde9e6d26ce39460fae0df046a2e1dcfc60b4ba91978013332de5584edd48f2e40c7315387f7738d3692bcd3868dac9f7c7179b679ecf426f3da09ec988b9a80ffea50db717166aebe741ca8d16e2ed6dba7cd7ce3b479d35c63c9a2c4ddd4972ce24d098afbeea7e7f1464788106859807f23f0af08ff22817f8a4588e6d2c9fa4273d69cacb79bf525dc136ee5d90825d8dac8fb6a02b8fe0f216a74d100d00700008301010100203d33cead0d8cb33323616dbe9a5ffbc9ba05f2b727d2be15c3832fa53e9260492fc88e9db27ca1cb7eb80ea3dcb514f23d4253ec80d5ed34b02b43a922ac95730100e70778da8d56bd8f1b45141f7f9cedb393d3e5201c97822288265220e704eb74d551d05050f0511d6119ef3c7b47de9dddccccda67a891083448744142114290e2aa4b135d2822b7202402698002e840e27fe0cdec7a77bdc7999b623fde7bf366de7bbff79b69fed179b7463edafdfe21c151310ff2f7b5b7cdeb817b345b10dcfba7dbfd6c632eb9bdb106a1e2e1ee2eedf397b65fec5636fb7ee88e1cc587828ba14363ed8592ebe9e531959c0aed9ca277c6d7b65ae8c4f1a8f24875259c0890754103a81b49c7f5c01da938e8bedc6b5157f331d5402a6b03a03a96e0303e04a58b56ab996b525fd59e04e5853e6bc45ce8ebddfa08a6ea1c3e9c09f0a1a7f76fa253378c85565b11c8802b0c4a383e8cc1cf4c5626946b75de3c33d9a5d3c321d5332c7bd1ce773dca85135189e16a908a5c782aa00769aa046827567408d649efc6254de5107459eb44ae4e97d93293b5a442994c611c8b2eae779feb538513402eb55acf7dfb00133a4de5cfbba1d070a09d81049379651357d8898883b39a3210a9692162378a1736b21871a65d1671d9c55680095e66f06cd983cf07a07990a58cc100a4048646070e1c445c526b37e1828593d4ea62d90b033fcbdb3346c985cf0538a95af1f7e70b6c9ed43288b467d5db3d9b9e1c5e4555c7a5c205df2e45aa6bc9df1c8deb653837ccfe392bb64a1ba722ee8c39a936d346b0bdd7ce6727ff397649b5863fed28eefbdc75f0b391c8d34db5700723ebb1bee0b1ee860c922f3d8d92af8e845b319710c07c5981704b26e174576293872919648f8421f22e6f5856805cd00c512f43897da84030043b674dbbb9ee4e0b25da5472a53fd5a04e24090908dda56b9693b0790a43906ac1f264de17d2b311c990c52e6e2aa7a9eaf94c98459987731ab19ec3e4cd09912d65c4a6b13415a9d407320cacff86028dac5b2a7b0d454966da46eff30089af54c855242bc7daac585a6a9ba64e624c05a6c58a8226fa32d52f396a8c0383841593989dd571304602c4ac25ff162ec956b08ada52a4229546f2f1dfec69d689241f97826a72e51871e2b8658d4286ce5a0a93c4621f9e3e5994fd9bed586450aefd2f94db71c468da4af5a5ad644298e3bd6eecf352770a470ca9b6ec9f0237258a4520ade3417ce5733c94f353917c7bfbcaab1f7efdca022f90bdef7eb977f8e56bc55ec7717554fbe693bc57c9de17772eb307778a0d88e3f7c71f3cf92aeba74fdfeafd0aecf078117938ee4270789ca16c7e7d98438c901f5e3ff68e664548e1d87be1e3a359060d421e3d7ee7cdfbb342b171bcf770fffe2c2b2b8e9d1f519097d004f7e8af3f7f2ed6ca06ecbff1a458117393b94b7ffa6dbbc67b3708c9ef1b78eb39c305a5b2ecb427ff024faa597d0001 DMLOG START_BLOCK 5 DMLOG CREATION_OP ROOT 0 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304004,"value_ex":101209,"consumed":1},"cpu_usage":{"last_ordinal":1262304004,"value_ex":268536,"consumed":101},"ram_usage":199629} -DMLOG TRX_OP CREATE onblock 0ade48384338de601ffbb688f58852a52cf6521566de6b975ca79fe2468d120e 0000000000000000000000000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed3232d905033b3d4b0000000000ea30550000000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b5dafd0f0596077e5010e7d7876a42e26a54669cb6ab0f1f073bf87b3d88a3043bc48e1625ffa8c398daca7e3f8bd15d4b2e191b8fa7d72547f72e57668630f3430000000000010000e104131a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88000000 -DMLOG APPLIED_TRANSACTION 5 0ade48384338de601ffbb688f58852a52cf6521566de6b975ca79fe2468d120e05000000043b3d4b010000000551fa877e4307b47a58bb19e36497ab2df3119c5c9cc1b9d80c307b5f01006400000000000000000000000000000000000000000001010000010000000000ea3055356768ae7dd9c5cb13c0d9456d144417f7a4834c9f71ebbc935a749e6f52cd861b000000000000001b00000000000000010000000000ea30551b0000000000000002020000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed3232d905033b3d4b0000000000ea30550000000000037b325d753bd9049355de4d8a48eee75fa3672264fa488e7f3cb464b5dafd0f0596077e5010e7d7876a42e26a54669cb6ab0f1f073bf87b3d88a3043bc48e1625ffa8c398daca7e3f8bd15d4b2e191b8fa7d72547f72e57668630f3430000000000010000e104131a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88000000000000000000000ade48384338de601ffbb688f58852a52cf6521566de6b975ca79fe2468d120e05000000043b3d4b010000000551fa877e4307b47a58bb19e36497ab2df3119c5c9cc1b9d80c307b5f0000000000000000 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304004,"value_ex":101996,"consumed":1},"cpu_usage":{"last_ordinal":1262304004,"value_ex":280111,"consumed":101},"ram_usage":199629} +DMLOG TRX_OP CREATE onblock 3a7e599683d2c0c0bd72111e3b4545288bedea9d59017f5aab92a95fc346d521 0000000000000000000000000000010000000000ea305500000000221acfa4010000000000ea305500000000a8ed3232f905033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc000000 +DMLOG APPLIED_TRANSACTION 5 3a7e599683d2c0c0bd72111e3b4545288bedea9d59017f5aab92a95fc346d52105000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d3201006400000000000000000000000000000000000000000001010000010000000000ea3055cf335d2018f12502cd38d1e00cdd86f5e0c7d69c417d27f48a89d18ce8220d5a1c000000000000001c00000000000000010000000000ea30551c0000000000000002020000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed3232f905033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc000000000000000000003a7e599683d2c0c0bd72111e3b4545288bedea9d59017f5aab92a95fc346d52105000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d320000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG PERM_OP INS 0 9 {"usage_id":8,"parent":0,"owner":"alice","name":"owner","last_updated":"2020-01-01T00:00:02.000","auth":{"threshold":1,"keys":[{"key":"EOS6JvuLaCqV8qHbSqUBVRPMo9N7V3vgE8YqHmweG568YmTDJ3opq","weight":1}],"accounts":[{"permission":{"actor":"alice","permission":"eosio.code"},"weight":1}],"waits":[]}} DMLOG PERM_OP INS 0 10 {"usage_id":9,"parent":9,"owner":"alice","name":"active","last_updated":"2020-01-01T00:00:02.000","auth":{"threshold":1,"keys":[{"key":"EOS8d5yGFrYpdXW1SUmaavRZKm5X7Bp9jK634JABCYPciwTkm7Wv2","weight":1}],"accounts":[{"permission":{"actor":"alice","permission":"eosio.code"},"weight":1}],"waits":[]}} DMLOG RLIMIT_OP ACCOUNT_LIMITS INS {"owner":"alice","net_weight":-1,"cpu_weight":-1,"ram_bytes":-1} DMLOG RLIMIT_OP ACCOUNT_USAGE INS {"owner":"alice","net_usage":{"last_ordinal":0,"value_ex":0,"consumed":0},"cpu_usage":{"last_ordinal":0,"value_ex":0,"consumed":0},"ram_usage":0} DMLOG RAM_OP 0 alice account add newaccount alice 2788 2788 -DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304004,"value_ex":102552,"consumed":233},"cpu_usage":{"last_ordinal":1262304004,"value_ex":280111,"consumed":2101},"ram_usage":199629} -DMLOG APPLIED_TRANSACTION 5 d2f164badf90bb8b9e827bd924baf8168dd8f207ecc205f5b43310ef86253aa405000000043b3d4b010000000551fa877e4307b47a58bb19e36497ab2df3119c5c9cc1b9d80c307b5f0100d00700001d0000000000000000e8000000000000000001010000010000000000ea30554895e298f1f3e56596649fb49ff53d0f76174ef57ef7c50f28152765cef1f97f1c000000000000001c00000000000000010000000000ea30551c0000000000000002020000000000ea30550000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea305501000000000000000000000000d2f164badf90bb8b9e827bd924baf8168dd8f207ecc205f5b43310ef86253aa405000000043b3d4b010000000551fa877e4307b47a58bb19e36497ab2df3119c5c9cc1b9d80c307b5f010000000000855c34e40a00000000000000000000000000 +DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304004,"value_ex":103339,"consumed":233},"cpu_usage":{"last_ordinal":1262304004,"value_ex":291686,"consumed":2101},"ram_usage":199629} +DMLOG APPLIED_TRANSACTION 5 357412c850b9a6be6c07837a297845c443c1c8e40f25b87a9750ac297e379dc005000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d320100d00700001d0000000000000000e8000000000000000001010000010000000000ea30554895e298f1f3e56596649fb49ff53d0f76174ef57ef7c50f28152765cef1f97f1d000000000000001d00000000000000010000000000ea30551d0000000000000002020000000000ea30550000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea305501000000000000000000000000357412c850b9a6be6c07837a297845c443c1c8e40f25b87a9750ac297e379dc005000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d32010000000000855c34e40a00000000000000000000000000 DMLOG CREATION_OP ROOT 0 DMLOG PERM_OP INS 0 11 {"usage_id":10,"parent":10,"owner":"alice","name":"test1","last_updated":"2020-01-01T00:00:02.000","auth":{"threshold":1,"keys":[],"accounts":[{"permission":{"actor":"eosio","permission":"active"},"weight":1}],"waits":[]}} DMLOG RAM_OP 0 11 auth add updateauth_create alice 3108 320 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"alice","net_usage":{"last_ordinal":1262304004,"value_ex":834,"consumed":144},"cpu_usage":{"last_ordinal":1262304004,"value_ex":11575,"consumed":2000},"ram_usage":3108} -DMLOG APPLIED_TRANSACTION 5 530de341efeac006a43329e4748583c9ef216a164c70c7b46a8e93042c45cd8a05000000043b3d4b010000000551fa877e4307b47a58bb19e36497ab2df3119c5c9cc1b9d80c307b5f0100d007000012000000000000000090000000000000000001010000010000000000ea3055f3d881d2f7fbf2f7cb6081aff84e7aca1dd3914a0948ef4fc9422e734e8d4d571d000000000000001d00000000000000010000000000855c34010000000000000002020000000000ea30550000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed323201000000000000000000000000530de341efeac006a43329e4748583c9ef216a164c70c7b46a8e93042c45cd8a05000000043b3d4b010000000551fa877e4307b47a58bb19e36497ab2df3119c5c9cc1b9d80c307b5f010000000000855c34400100000000000000000000000000 -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":145068889,"consumed":8000},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":382895892,"consumed":4449},"pending_net_usage":376,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} -DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":5,"value_ex":146993315,"consumed":520},"average_block_cpu_usage":{"last_ordinal":5,"value_ex":413871759,"consumed":4480},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1052778,"virtual_cpu_limit":200800} -DMLOG ACCEPTED_BLOCK 5 05000000050000000400000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010001b2cd0fd8d0aeb0983cf5b79b35e97f42f204914726c831b95c1ff896ca7cc1f70400000000000000010000000000ea305505000000010000000000ea305504000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000551fa877e4307b47a58bb19e36497ab2df3119c5c9cc1b9d80c307b5f043b3d4b0000000000ea305500000000000446ce40fcba331770d4e40c1a69d054d3a9a5ed89ef08b50cc808e32529e6fd108fe2b5c29c60c4d10b3bcd6dd68fbbaeb8eda2417ea361750429ed07182c0649523b9bcbb941da3c9ba69b7fdd2a061be2e8e19bd532c4532c674074000000000000001f64905c5f3f6b6fea6be1479d459f26f49dabe66f6452d029b4aac534bdae794a5bc74c010be03a9ac8bcd1af835910bff6619dcc993a6b3cda9ef986372bcf900000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001140ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001043b3d4b0000000000ea305500000000000446ce40fcba331770d4e40c1a69d054d3a9a5ed89ef08b50cc808e32529e6fd108fe2b5c29c60c4d10b3bcd6dd68fbbaeb8eda2417ea361750429ed07182c0649523b9bcbb941da3c9ba69b7fdd2a061be2e8e19bd532c4532c674074000000000000001f64905c5f3f6b6fea6be1479d459f26f49dabe66f6452d029b4aac534bdae794a5bc74c010be03a9ac8bcd1af835910bff6619dcc993a6b3cda9ef986372bcf900200d00700001d0101001f281f9a1a1c1db3802dcc9722bc82373b1b7e5e02ee3c23555be869da51384317257214aaabf8797fe97ff3d5c7366353d197575f7ad7dc07b8f6b48f251b39ce0000bd0107e10b5e0400ba33177000000000010000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea30550100000000d0070000120101001f111f9dacd4b0ca94c80782ea19e40bccd1d211a4ef502ce83a27752116ccd86f1063361a90577bd5654df73be79ba08d45a08d786975c9b93ef6f249558beca000006307e10b5e0400ba33177000000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed3232010000000001 +DMLOG APPLIED_TRANSACTION 5 c2e8f254cf27feb007d7f43ed2cf9f20b4993f425de7b4632997cb7f49de509705000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d320100d007000012000000000000000090000000000000000001010000010000000000ea3055f3d881d2f7fbf2f7cb6081aff84e7aca1dd3914a0948ef4fc9422e734e8d4d571e000000000000001e00000000000000010000000000855c34010000000000000002020000000000ea30550000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed323201000000000000000000000000c2e8f254cf27feb007d7f43ed2cf9f20b4993f425de7b4632997cb7f49de509705000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d32010000000000855c34400100000000000000000000000000 +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":146193333,"consumed":8009},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":399423669,"consumed":4466},"pending_net_usage":376,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} +DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":5,"value_ex":148108389,"consumed":521},"average_block_cpu_usage":{"last_ordinal":5,"value_ex":430261805,"consumed":4497},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1052778,"virtual_cpu_limit":200800} +DMLOG ACCEPTED_BLOCK 5 05000000050000000400000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100013a220582e0cfa7a17f55cebb532b2a1d90d2ef2ae30469faa539ba199e2244a40400000000000000010000000000ea305505000000010000000000ea305504000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d32043b3d4b0000000000ea3055000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e56cbb1751058d6346085c90810b9506a2813958022794c157d0182253441a192032e84b542636e8b3efa7359943ee5c039d3ae19fbeb432871652ecfdc57fb22d000000000000001f78ee459e123dba62f8d8ae4168bec01f85253e5d30cc245bedf803fe712c5680524933231df7361e5d18731b8c0a44f48a696cc74dfd22755d41f031787509330000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001150ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fccad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001043b3d4b0000000000ea3055000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e56cbb1751058d6346085c90810b9506a2813958022794c157d0182253441a192032e84b542636e8b3efa7359943ee5c039d3ae19fbeb432871652ecfdc57fb22d000000000000001f78ee459e123dba62f8d8ae4168bec01f85253e5d30cc245bedf803fe712c5680524933231df7361e5d18731b8c0a44f48a696cc74dfd22755d41f031787509330200d00700001d0101002018a75bd433fc0c63bdc343b1b68346656c45b3700cf701b9d12fda5600ba097641950d06262f8e4b03976ebe137be9eb3d186ebf69066e9a7104228ed968d9120000bd0107e10b5e04002f98b2d600000000010000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea30550100000000d0070000120101001f0de388764e716146ab616ff095376ef69daf2fd6c2f244e0f69ad985857da8772a682aaa81862225fd75f739faf1cdb5879e4bbf2ce6133f7aed2f8d2ff4fe5700006307e10b5e04002f98b2d600000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed3232010000000001 From 3b78eb96a4fd34c79b24bebe238c7ddb54a52e6a Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 15:59:14 -0500 Subject: [PATCH 048/151] GH-1533 Remove failing test since scheduled to be fixed by GH-1531 --- libraries/libfc/test/test_bls.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 2e2d5ca00b..6246a2a27b 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -114,6 +114,8 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_hotstuff_types) try { } FC_LOG_AND_RETHROW(); +#warning test being worked under https://github.com/AntelopeIO/leap/issues/1531 +/* //test a aggregate signature from string BOOST_AUTO_TEST_CASE(bls_sig_verif_string_multi) try { @@ -144,7 +146,7 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_string_multi) try { BOOST_CHECK_EQUAL(ok, true); } FC_LOG_AND_RETHROW(); - +*/ //test serialization / deserialization of private key, public key and signature BOOST_AUTO_TEST_CASE(bls_serialization_test) try { From c778050f47873d81e2706aca66485192f730a853 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 18 Aug 2023 16:26:42 -0500 Subject: [PATCH 049/151] Minor cleanup --- libraries/libfc/include/fc/crypto/base64.hpp | 8 ++++---- libraries/libfc/include/fc/crypto/private_key.hpp | 2 +- libraries/libfc/src/crypto/base64.cpp | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/base64.hpp b/libraries/libfc/include/fc/crypto/base64.hpp index d57e2d11e5..67d48af782 100644 --- a/libraries/libfc/include/fc/crypto/base64.hpp +++ b/libraries/libfc/include/fc/crypto/base64.hpp @@ -5,11 +5,11 @@ namespace fc { std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len); inline std::string base64_encode(char const* bytes_to_encode, unsigned int in_len) { return base64_encode( (unsigned char const*)bytes_to_encode, in_len); } -std::string base64_encode( const std::string_view& enc ); -std::string base64_decode( const std::string_view& encoded_string); +std::string base64_encode( std::string_view enc ); +std::string base64_decode( std::string_view encoded_string); std::string base64url_encode(unsigned char const* bytes_to_encode, unsigned int in_len); inline std::string base64url_encode(char const* bytes_to_encode, unsigned int in_len) { return base64url_encode( (unsigned char const*)bytes_to_encode, in_len); } -std::string base64url_encode( const std::string_view& enc ); -std::string base64url_decode( const std::string_view& encoded_string); +std::string base64url_encode( std::string_view enc ); +std::string base64url_decode( std::string_view encoded_string); } // namespace fc diff --git a/libraries/libfc/include/fc/crypto/private_key.hpp b/libraries/libfc/include/fc/crypto/private_key.hpp index cc80757a8c..8c296677ba 100644 --- a/libraries/libfc/include/fc/crypto/private_key.hpp +++ b/libraries/libfc/include/fc/crypto/private_key.hpp @@ -53,7 +53,7 @@ namespace fc { namespace crypto { storage_type _storage; private_key( storage_type&& other_storage ) - :_storage(other_storage) + :_storage(std::move(other_storage)) {} friend bool operator == ( const private_key& p1, const private_key& p2); diff --git a/libraries/libfc/src/crypto/base64.cpp b/libraries/libfc/src/crypto/base64.cpp index d5369dcbad..d7308ac87b 100644 --- a/libraries/libfc/src/crypto/base64.cpp +++ b/libraries/libfc/src/crypto/base64.cpp @@ -215,7 +215,7 @@ std::string base64_encode(unsigned char const* bytes_to_encode, size_t in_len, b } template -static std::string decode(String const& encoded_string, bool remove_linebreaks) { +static std::string decode(const String& encoded_string, bool remove_linebreaks) { // // decode(…) is templated so that it can be used with String = const std::string& // or std::string_view (requires at least C++17) @@ -343,20 +343,20 @@ std::string base64_decode(std::string_view s, bool remove_linebreaks) { std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { return base64_encode(bytes_to_encode, in_len, false); } -std::string base64_encode(const std::string_view& enc) { +std::string base64_encode(std::string_view enc) { return base64_encode(enc, false); } -std::string base64_decode(const std::string_view& encoded_string) { +std::string base64_decode(std::string_view encoded_string) { return base64_decode(encoded_string, false); } std::string base64url_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { return base64_encode(bytes_to_encode, in_len, true); } -std::string base64url_encode(const std::string_view& enc) { +std::string base64url_encode(std::string_view enc) { return base64_encode(enc, true); } -std::string base64url_decode(const std::string_view& encoded_string) { +std::string base64url_decode(std::string_view encoded_string) { return base64_decode(encoded_string, true); } From 2cfd42c36d08010decb6b538daf5ee7ad43a1a55 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Mon, 21 Aug 2023 18:07:57 +0000 Subject: [PATCH 050/151] Clean up of bls_private_key, bls_public_key and bls_signature, removed string prefix, added base58 to_string + parsing code for bls_private_key + unit test, removed old unit test --- .../include/fc/crypto/bls_private_key.hpp | 6 +- .../include/fc/crypto/bls_public_key.hpp | 26 -------- .../libfc/include/fc/crypto/bls_signature.hpp | 4 +- .../libfc/src/crypto/bls_private_key.cpp | 44 ++++--------- libraries/libfc/src/crypto/bls_public_key.cpp | 44 ++----------- libraries/libfc/src/crypto/bls_signature.cpp | 54 +--------------- libraries/libfc/test/test_bls.cpp | 62 +++++++++---------- 7 files changed, 49 insertions(+), 191 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 0738b248e6..c28ef57965 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -5,14 +5,10 @@ namespace fc::crypto::blslib { - namespace config { - constexpr const char* bls_private_key_base_prefix = "PVT"; - constexpr const char* bls_private_key_prefix = "BLS"; - }; - class bls_private_key { public: + bls_private_key() = default; bls_private_key( bls_private_key&& ) = default; bls_private_key( const bls_private_key& ) = default; diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index b805252de3..d8bf0fbee1 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -12,13 +12,6 @@ namespace fc { namespace crypto { namespace blslib { using namespace std; - namespace config { - constexpr const char* bls_public_key_legacy_prefix = "EOS"; - constexpr const char* bls_public_key_base_prefix = "PUB"; - constexpr const char* bls_public_key_prefix = "BLS"; - - }; - class bls_public_key { public: @@ -32,24 +25,8 @@ namespace fc { namespace crypto { namespace blslib { _pkey = pkey; } -/* bls_public_key( G1Element pkey ){ - _pkey = pkey.Serialize(); - } -*/ - //bls_public_key( const bls_signature& c, const sha256& digest, bool check_canonical = true ); - -/* bls_public_key( storage_type&& other_storage ) - :_storage(forward(other_storage)) - {} -*/ - bool valid()const; - - size_t which()const; - // serialize to/from string explicit bls_public_key(const string& base58str); - //std::string to_string() const; - //std::string to_string() ; std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; @@ -60,9 +37,6 @@ 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); friend struct reflector; friend class bls_private_key; }; // bls_public_key diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index 3c07333cbf..fce491e9c0 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -42,7 +42,7 @@ namespace fc { namespace crypto { namespace blslib { // size_t which() const; - size_t variable_size() const; + //size_t variable_size() const; bls12_381::g2 _sig; @@ -58,7 +58,7 @@ namespace fc { namespace crypto { namespace blslib { //friend bool operator == ( const bls_signature& p1, const bls_signature& p2); //friend bool operator != ( const bls_signature& p1, const bls_signature& p2); //friend bool operator < ( const bls_signature& p1, const bls_signature& p2); - friend std::size_t hash_value(const bls_signature& b); //not cryptographic; for containers + //friend std::size_t hash_value(const bls_signature& b); //not cryptographic; for containers friend bool operator == ( const bls_signature& p1, const bls_signature& p2); friend struct reflector; friend class bls_private_key; diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index af5561485b..c11b1d15bc 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -25,38 +25,17 @@ namespace fc::crypto::blslib { return bls_private_key(v); } - template - Data from_wif( const string& wif_key ) + static vector priv_parse_base58(const string& base58str) { - /* auto wif_bytes = from_base58(wif_key); - FC_ASSERT(wif_bytes.size() >= 5); - auto key_bytes = vector(wif_bytes.begin() + 1, wif_bytes.end() - 4); - fc::sha256 check = fc::sha256::hash(wif_bytes.data(), wif_bytes.size() - 4); - fc::sha256 check2 = fc::sha256::hash(check); + std::vector v1 = fc::from_base58(base58str); - FC_ASSERT(memcmp( (char*)&check, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 || - memcmp( (char*)&check2, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 ); + FC_ASSERT(v1.size() == 32); - return Data(fc::variant(key_bytes).as());*/ - } + std::vector v2(32); - static vector priv_parse_base58(const string& base58str) - { - const auto pivot = base58str.find('_'); -/* - if (pivot == std::string::npos) { - // wif import - using default_type = std::variant_alternative_t<0, bls_private_key::storage_type>; - return bls_private_key::storage_type(from_wif(base58str)); - } else { - constexpr auto prefix = config::private_key_base_prefix; - const auto prefix_str = base58str.substr(0, pivot); - FC_ASSERT(prefix == prefix_str, "Private Key has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str)); - - auto data_str = base58str.substr(pivot + 1); - FC_ASSERT(!data_str.empty(), "Private Key has no data: ${str}", ("str", base58str)); - return base58_str_parser::apply(data_str); - }*/ + std::copy(v1.begin(), v1.end(), v2.begin()); + + return v2; } bls_private_key::bls_private_key(const std::string& base58str) @@ -66,12 +45,13 @@ namespace fc::crypto::blslib { std::string bls_private_key::to_string(const fc::yield_function_t& yield) const { - /*PrivateKey pk = AugSchemeMPL().KeyGen(_seed); + std::vector v2(32); + std::copy(_seed.begin(), _seed.end(), v2.begin()); + + std::string data_str = fc::to_base58(v2, yield); - vector pkBytes pk.Serialize() + return data_str; - auto data_str = Util::HexStr(pkBytes); - return std::string(config::private_key_base_prefix) + "_" + data_str;*/ } } // fc::crypto::blslib diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 4d4c888cf5..29ac4f681f 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -4,39 +4,10 @@ namespace fc { namespace crypto { namespace blslib { - /* struct recovery_visitor : fc::visitor { - recovery_visitor(const sha256& digest, bool check_canonical) - :_digest(digest) - ,_check_canonical(check_canonical) - {} - - template - bls_public_key::storage_type operator()(const SignatureType& s) const { - return bls_public_key::storage_type(s.recover(_digest, _check_canonical)); - } - - const sha256& _digest; - bool _check_canonical; - }; - - bls_public_key::bls_public_key( const bls_signature& c, const sha256& digest, bool check_canonical ) - :_storage(std::visit(recovery_visitor(digest, check_canonical), c._storage)) - { - } - - size_t bls_public_key::which() const { - return _storage.index(); - }*/ - static bls12_381::g1 parse_base58(const std::string& base58str) { - constexpr auto prefix = config::bls_public_key_base_prefix; - const auto pivot = base58str.find('_'); - const auto prefix_str = base58str.substr(0, pivot); - auto data_str = base58str.substr(pivot + 1); - - std::vector v1 = fc::from_base58(data_str); + std::vector v1 = fc::from_base58(base58str); FC_ASSERT(v1.size() == 48); std::array v2; @@ -50,13 +21,6 @@ namespace fc { namespace crypto { namespace blslib { :_pkey(parse_base58(base58str)) {} - - bool bls_public_key::valid()const - { - //return std::visit(is_valid_visitor(), _storage); - } - - std::string bls_public_key::to_string(const fc::yield_function_t& yield)const { std::vector v2; @@ -64,10 +28,10 @@ namespace fc { namespace crypto { namespace blslib { std::copy(bytes.begin(), bytes.end(), std::back_inserter(v2)); std::string data_str = fc::to_base58(v2, yield); - - //std::string data_str = Util::HexStr(_pkey); - return std::string(config::bls_public_key_base_prefix) + "_" + data_str; + //return std::string(config::bls_public_key_base_prefix) + "_" + data_str; + return data_str; + } diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 6e2c0732a8..151728f115 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -4,29 +4,11 @@ namespace fc { namespace crypto { namespace blslib { - struct hash_visitor : public fc::visitor { -/* template - size_t operator()(const SigType& sig) const { - static_assert(sizeof(sig._data.data) == 65, "sig size is expected to be 65"); - //signatures are two bignums: r & s. Just add up least significant digits of the two - return *(size_t*)&sig._data.data[32-sizeof(size_t)] + *(size_t*)&sig._data.data[64-sizeof(size_t)]; - } - - size_t operator()(const webauthn::bls_signature& sig) const { - return sig.get_hash(); - }*/ - }; static bls12_381::g2 sig_parse_base58(const std::string& base58str) { try { - - const auto pivot = base58str.find('_'); - auto base_str = base58str.substr(pivot + 1); - const auto pivot2 = base_str.find('_'); - auto data_str = base_str.substr(pivot2 + 1); - - std::vector v1 = fc::from_base58(data_str); + std::vector v1 = fc::from_base58(base58str); FC_ASSERT(v1.size() == 96); std::array v2; @@ -40,25 +22,6 @@ namespace fc { namespace crypto { namespace blslib { :_sig(sig_parse_base58(base58str)) {} -// size_t bls_signature::which() const { -// //return _storage.index(); -// } - - - //template struct overloaded : Ts... { using Ts::operator()...; }; - //template overloaded(Ts...) -> overloaded; - - size_t bls_signature::variable_size() const { - /* return std::visit(overloaded { - [&](const auto& k1r1) { - return static_cast(0); - }, - [&](const webauthn::bls_signature& wa) { - return static_cast(wa.variable_size()); - } - }, _storage);*/ - } - std::string bls_signature::to_string(const fc::yield_function_t& yield) const { @@ -68,7 +31,7 @@ namespace fc { namespace crypto { namespace blslib { std::string data_str = fc::to_base58(v2, yield); - return std::string(config::bls_signature_base_prefix) + "_" + std::string(config::bls_signature_prefix) + "_" + data_str; + return data_str; } @@ -81,19 +44,6 @@ namespace fc { namespace crypto { namespace blslib { return p1._sig == p2._sig; } -/* - bool operator != ( const bls_signature& p1, const bls_signature& p2) { - return !eq_comparator::apply(p1._storage, p2._storage); - } - - bool operator < ( const bls_signature& p1, const bls_signature& p2) - { - return less_comparator::apply(p1._storage, p2._storage); - } -*/ - size_t hash_value(const bls_signature& b) { - // return std::visit(hash_visitor(), b._storage); - } } } } // fc::crypto::blslib namespace fc diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 6246a2a27b..6b4a5c1bf2 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -114,40 +114,6 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_hotstuff_types) try { } FC_LOG_AND_RETHROW(); -#warning test being worked under https://github.com/AntelopeIO/leap/issues/1531 -/* -//test a aggregate signature from string -BOOST_AUTO_TEST_CASE(bls_sig_verif_string_multi) try { - - bls_signature test_sig_single = bls_signature("SIG_BLS_23PuSu1B72cPe6wxGkKjAaaZqA1Ph79zSoW7omsKKUrnprbA3cJCJVhT48QKUG6ofjYTTg4BA4TrVENWyrxjTomwLX6TGdVg2RYhKH7Kk9X23K5ohuhKQcWQ6AwJJGVSbSp4"); - std::vector message_4 = {143,10,193,195,104,126,124,222,124,64,177,164,240,234,110,18,142,236,191,66,223,47,235,248,75,9,172,99,178,26,239,78}; - bls_private_key sk = bls_private_key(seed_1); - - bls_public_key agg_key = sk.get_public_key(); - bls_signature agg_sig = test_sig_single; - - cout << 0 << "\n"; - cout << agg_key.to_string() << "\n"; - cout << agg_sig.to_string() << "\n"; - - for (int i = 1 ;i<14;i++){ - - agg_key = aggregate({agg_key, sk.get_public_key() }); - agg_sig = aggregate({agg_sig, test_sig_single}); - - cout << i << "\n"; - cout << agg_key.to_string() << "\n"; - cout << agg_sig.to_string() << "\n"; - - } - - bool ok = verify(agg_key, message_4, agg_sig); - - BOOST_CHECK_EQUAL(ok, true); - -} FC_LOG_AND_RETHROW(); -*/ - //test serialization / deserialization of private key, public key and signature BOOST_AUTO_TEST_CASE(bls_serialization_test) try { @@ -280,5 +246,33 @@ BOOST_AUTO_TEST_CASE(bls_bad_sig_verif) try { } FC_LOG_AND_RETHROW(); +//test private key base58 encoding +BOOST_AUTO_TEST_CASE(bls_private_key_string_encoding) try { + + bls_private_key sk = bls_private_key(seed_1); + + bls_public_key pk = sk.get_public_key(); + + std::string priv_base58_str = sk.to_string(); + + //cout << "priv_base58_str : " << priv_base58_str << "\n"; + + bls_private_key sk2 = bls_private_key(priv_base58_str); + + //cout << "sk2 : " << sk2.to_string() << "\n"; + + bls_signature signature = sk2.sign(message_1); + + //cout << "pk : " << pk.to_string() << "\n"; + //cout << "signature : " << signature.to_string() << "\n"; + + // Verify the signature + bool ok = verify(pk, message_1, signature); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); + + BOOST_AUTO_TEST_SUITE_END() From 4b373a0eb23dfddb6516588352a5a586e7ad4c71 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Mon, 21 Aug 2023 20:00:05 +0000 Subject: [PATCH 051/151] Added wif import / export + checksum based on the fc::private_key model --- .../libfc/src/crypto/bls_private_key.cpp | 51 +++++++++++++++---- libraries/libfc/test/test_bls.cpp | 7 ++- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index c11b1d15bc..917ce3962d 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -25,19 +25,51 @@ namespace fc::crypto::blslib { return bls_private_key(v); } - static vector priv_parse_base58(const string& base58str) + string to_wif(vector secret, const fc::yield_function_t& yield ) { - std::vector v1 = fc::from_base58(base58str); + FC_ASSERT(secret.size() == 32); - FC_ASSERT(v1.size() == 32); + std::array v2; - std::vector v2(32); + std::copy(secret.begin(), secret.end(), v2.begin()); + + const size_t size_of_data_to_hash = 32 + 1; + const size_t size_of_hash_bytes = 4; + char data[size_of_data_to_hash + size_of_hash_bytes]; + data[0] = (char)0x80; // this is the Bitcoin MainNet code + memcpy(&data[1], (const char*)&v2, 32); + sha256 digest = sha256::hash(data, size_of_data_to_hash); + digest = sha256::hash(digest); + memcpy(data + size_of_data_to_hash, (char*)&digest, size_of_hash_bytes); + + return to_base58(data, sizeof(data), yield); + } + + std::vector from_wif( const string& wif_key ) + { + auto wif_bytes = from_base58(wif_key); + FC_ASSERT(wif_bytes.size() >= 5); - std::copy(v1.begin(), v1.end(), v2.begin()); + auto key_bytes = vector(wif_bytes.begin() + 1, wif_bytes.end() - 4); + fc::sha256 check = fc::sha256::hash(wif_bytes.data(), wif_bytes.size() - 4); + fc::sha256 check2 = fc::sha256::hash(check); + + FC_ASSERT(memcmp( (char*)&check, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 || + memcmp( (char*)&check2, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 ); + + std::vector v2(32); + std::copy(key_bytes.begin(), key_bytes.end(), v2.begin()); return v2; } + static vector priv_parse_base58(const string& base58str) + { + cout << base58str << "\n"; + + return from_wif(base58str); + } + bls_private_key::bls_private_key(const std::string& base58str) :_seed(priv_parse_base58(base58str)) {} @@ -45,13 +77,12 @@ namespace fc::crypto::blslib { std::string bls_private_key::to_string(const fc::yield_function_t& yield) const { - std::vector v2(32); - std::copy(_seed.begin(), _seed.end(), v2.begin()); - - std::string data_str = fc::to_base58(v2, yield); + FC_ASSERT(_seed.size() == 32); + string wif = to_wif(_seed, yield); - return data_str; + cout << wif << "\n"; + return wif; } } // fc::crypto::blslib diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 6b4a5c1bf2..07cf33c4dc 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -255,16 +255,15 @@ BOOST_AUTO_TEST_CASE(bls_private_key_string_encoding) try { std::string priv_base58_str = sk.to_string(); - //cout << "priv_base58_str : " << priv_base58_str << "\n"; + cout << "priv_base58_str : " << priv_base58_str << "\n"; bls_private_key sk2 = bls_private_key(priv_base58_str); - //cout << "sk2 : " << sk2.to_string() << "\n"; + cout << "sk2 : " << sk2.to_string() << "\n"; bls_signature signature = sk2.sign(message_1); - //cout << "pk : " << pk.to_string() << "\n"; - //cout << "signature : " << signature.to_string() << "\n"; + cout << "signature : " << signature.to_string() << "\n"; // Verify the signature bool ok = verify(pk, message_1, signature); From 23d049d6f115d785c4ee1e50d0ac84eae6676c9a Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Mon, 21 Aug 2023 20:01:08 +0000 Subject: [PATCH 052/151] remove cout statements --- libraries/libfc/src/crypto/bls_private_key.cpp | 4 ++-- libraries/libfc/test/test_bls.cpp | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index 917ce3962d..6cce1a3266 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -65,7 +65,7 @@ namespace fc::crypto::blslib { static vector priv_parse_base58(const string& base58str) { - cout << base58str << "\n"; + //cout << base58str << "\n"; return from_wif(base58str); } @@ -80,7 +80,7 @@ namespace fc::crypto::blslib { FC_ASSERT(_seed.size() == 32); string wif = to_wif(_seed, yield); - cout << wif << "\n"; + //cout << wif << "\n"; return wif; } diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 07cf33c4dc..eabc553eb8 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -252,18 +252,18 @@ BOOST_AUTO_TEST_CASE(bls_private_key_string_encoding) try { bls_private_key sk = bls_private_key(seed_1); bls_public_key pk = sk.get_public_key(); - + std::string priv_base58_str = sk.to_string(); - cout << "priv_base58_str : " << priv_base58_str << "\n"; + //cout << "priv_base58_str : " << priv_base58_str << "\n"; bls_private_key sk2 = bls_private_key(priv_base58_str); - cout << "sk2 : " << sk2.to_string() << "\n"; + //cout << "sk2 : " << sk2.to_string() << "\n"; bls_signature signature = sk2.sign(message_1); - cout << "signature : " << signature.to_string() << "\n"; + //cout << "signature : " << signature.to_string() << "\n"; // Verify the signature bool ok = verify(pk, message_1, signature); From 835103477fe493bd7e03ec10455694facea0c535 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 21 Aug 2023 16:50:49 -0500 Subject: [PATCH 053/151] Quick cleanups --- libraries/chain/controller.cpp | 3 +- .../chain/include/eosio/chain/config.hpp | 2 +- .../chain/include/eosio/chain/hotstuff.hpp | 15 +- .../chain/include/eosio/chain/qc_database.hpp | 89 -- libraries/chain/qc_database.cpp | 492 ------- libraries/chain/webassembly/crypto.cpp | 4 - libraries/hotstuff/CMakeLists.txt | 1 - libraries/hotstuff/chain_pacemaker.cpp | 37 +- .../include/eosio/hotstuff/base_pacemaker.hpp | 38 +- .../eosio/hotstuff/chain_pacemaker.hpp | 12 +- .../include/eosio/hotstuff/qc_chain.hpp | 66 +- .../include/eosio/hotstuff/test_pacemaker.hpp | 2 +- libraries/hotstuff/qc_chain.cpp | 23 +- libraries/hotstuff/test/CMakeLists.txt | 2 +- .../test/Testing/Temporary/CTestCostData.txt | 1 - .../test/Testing/Temporary/LastTest.log | 3 - .../hotstuff/{ => test}/test_pacemaker.cpp | 30 +- .../eosio/chain_plugin/chain_plugin.hpp | 2 +- .../eosio/producer_plugin/producer_plugin.hpp | 1 - plugins/producer_plugin/producer_plugin.cpp | 4 +- plugins/producer_plugin/qc_chain.cpp.bkp | 1216 ----------------- plugins/producer_plugin/qc_chain.old.cpp | 573 -------- plugins/producer_plugin/qc_chain.old2.cpp | 1216 ----------------- 23 files changed, 118 insertions(+), 3714 deletions(-) delete mode 100644 libraries/chain/include/eosio/chain/qc_database.hpp delete mode 100644 libraries/chain/qc_database.cpp delete mode 100644 libraries/hotstuff/test/Testing/Temporary/CTestCostData.txt delete mode 100644 libraries/hotstuff/test/Testing/Temporary/LastTest.log rename libraries/hotstuff/{ => test}/test_pacemaker.cpp (90%) delete mode 100644 plugins/producer_plugin/qc_chain.cpp.bkp delete mode 100644 plugins/producer_plugin/qc_chain.old.cpp delete mode 100644 plugins/producer_plugin/qc_chain.old2.cpp diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 000658a100..037dc6de50 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1696,8 +1696,6 @@ struct controller_impl { { EOS_ASSERT( !pending, block_validate_exception, "pending block already exists" ); - //ilog("starting block... "); - emit( self.block_start, head->block_num + 1 ); // at block level, no transaction specific logging is possible @@ -3878,6 +3876,7 @@ void controller_impl::on_activation( template<> void controller_impl::on_activation() { db.modify( db.get(), [&]( auto& ps ) { +#warning host functions to set proposers, leaders, finalizers/validators // FIXME/TODO: host functions to set proposers, leaders, finalizers/validators } ); } diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 4dae979f32..6448c6ae59 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -12,7 +12,7 @@ const static auto reversible_blocks_dir_name = "reversible"; const static auto default_state_dir_name = "state"; const static auto forkdb_filename = "fork_db.dat"; -const static auto qcdb_filename = "qc_db.dat"; +const static auto qcdb_filename = "qc_db.dat"; const static auto default_state_size = 1*1024*1024*1024ll; const static auto default_state_guard_size = 128*1024*1024ll; diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 8c8636b598..011e91d63d 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -1,22 +1,17 @@ #pragma once #include #include -#include #include #include #include #include -namespace eosio { namespace chain { +namespace eosio::chain { const block_id_type NULL_BLOCK_ID = block_id_type("00"); const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - static uint32_t compute_block_num(block_id_type block_id) { - return fc::endian_reverse_u32(block_id._hash[0]); - } - - static uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) { + inline uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) { return (uint64_t{block_height} << 32) | phase_counter; } @@ -46,8 +41,8 @@ namespace eosio { namespace chain { quorum_certificate justify; //justification uint8_t phase_counter = 0; - uint32_t block_num() const { return compute_block_num(block_id); } - uint64_t get_height() const { return compute_height(compute_block_num(block_id), phase_counter); }; + uint32_t block_num() const { return block_header::num_from_id(block_id); } + uint64_t get_height() const { return compute_height(block_header::num_from_id(block_id), phase_counter); }; }; struct hs_new_block_message { @@ -80,7 +75,7 @@ namespace eosio { namespace chain { using hs_new_view_message_ptr = std::shared_ptr; using hs_new_block_message_ptr = std::shared_ptr; -}} //eosio::chain +} //eosio::chain FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); FC_REFLECT(eosio::chain::extended_schedule, (producer_schedule)(bls_pub_keys)); diff --git a/libraries/chain/include/eosio/chain/qc_database.hpp b/libraries/chain/include/eosio/chain/qc_database.hpp deleted file mode 100644 index a0d73fc1dc..0000000000 --- a/libraries/chain/include/eosio/chain/qc_database.hpp +++ /dev/null @@ -1,89 +0,0 @@ -#pragma once -#include -#include -#include - -namespace eosio { namespace chain { - - using boost::signals2::signal; - - struct qc_database_impl; - - class qc_database { - public: - - explicit qc_database( const fc::path& data_dir ); - ~qc_database(); - - void open( const std::function&, - const vector& )>& validator ); - void close(); - - //block_header_state_ptr get_block_header( const block_id_type& id )const; - //block_state_ptr get_block( const block_id_type& id )const; - - /** - * Purges any existing blocks from the fork database and resets the root block_header_state to the provided value. - * The head will also be reset to point to the root. - */ - //void reset( const block_header_state& root_bhs ); - - /** - * Removes validated flag from all blocks in fork database and resets head to point to the root. - */ - //void rollback_head_to_root(); - - /** - * Advance root block forward to some other block in the tree. - */ - //void advance_root( const block_id_type& id ); - - /** - * Add block state to fork database. - * Must link to existing block in fork database or the root. - */ - //void add( const block_state_ptr& next_block, bool ignore_duplicate = false ); - - //void remove( const block_id_type& id ); - - //const block_state_ptr& root()const; - //const block_state_ptr& head()const; - //block_state_ptr pending_head()const; - - /** - * Returns the sequence of block states resulting from trimming the branch from the - * root block (exclusive) to the block with an id of `h` (inclusive) by removing any - * block states corresponding to block numbers greater than `trim_after_block_num`. - * - * The order of the sequence is in descending block number order. - * A block with an id of `h` must exist in the fork database otherwise this method will throw an exception. - */ - //branch_type fetch_branch( const block_id_type& h, uint32_t trim_after_block_num = std::numeric_limits::max() )const; - - - /** - * Returns the block state with a block number of `block_num` that is on the branch that - * contains a block with an id of`h`, or the empty shared pointer if no such block can be found. - */ - //block_state_ptr search_on_branch( const block_id_type& h, uint32_t block_num )const; - - /** - * Given two head blocks, return two branches of the fork graph that - * end with a common ancestor (same prior block) - */ - //pair< branch_type, branch_type > fetch_branch_from( const block_id_type& first, const block_id_type& second )const; - - - //void mark_valid( const block_state_ptr& h ); - - //static const uint32_t magic_number; - - //static const uint32_t min_supported_version; - //static const uint32_t max_supported_version; - - private: - //unique_ptr my; - }; - -} } /// eosio::chain diff --git a/libraries/chain/qc_database.cpp b/libraries/chain/qc_database.cpp deleted file mode 100644 index 37fbd4918e..0000000000 --- a/libraries/chain/qc_database.cpp +++ /dev/null @@ -1,492 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace eosio { namespace chain { - using boost::multi_index_container; - using namespace boost::multi_index; - - //const uint32_t fork_database::magic_number = 0x30510FDB; - - //const uint32_t fork_database::min_supported_version = 1; - //const uint32_t fork_database::max_supported_version = 1; - - // work around block_state::is_valid being private - //inline bool block_state_is_valid( const block_state& bs ) { - // return bs.is_valid(); - //} - - /** - * History: - * Version 1: initial version of the new refactored fork database portable format - */ - - //struct by_block_id; - //struct by_lib_block_num; - //struct by_prev; - /*typedef multi_index_container< - block_state_ptr, - indexed_by< - hashed_unique< tag, member, std::hash>, - ordered_non_unique< tag, const_mem_fun >, - ordered_unique< tag, - composite_key< block_state, - global_fun, - member, - member, - member - >, - composite_key_compare< - std::greater, - std::greater, - std::greater, - sha256_less - > - > - > - > fork_multi_index_type;*/ - -/* bool first_preferred( const block_header_state& lhs, const block_header_state& rhs ) { - return std::tie( lhs.dpos_irreversible_blocknum, lhs.block_num ) - > std::tie( rhs.dpos_irreversible_blocknum, rhs.block_num ); - } -*/ - struct qc_database_impl { - qc_database_impl( qc_database& self, const fc::path& data_dir ) - :self(self) - ,datadir(data_dir) - {} - - qc_database& self; - //fork_multi_index_type index; - //block_state_ptr root; // Only uses the block_header_state portion - //block_state_ptr head; - fc::path datadir; - - /*void add( const block_state_ptr& n, - bool ignore_duplicate, bool validate, - const std::function&, - const vector& )>& validator );*/ - }; - - - fork_database::qc_database( const fc::path& data_dir ) - :my( new qc_database_impl( *this, data_dir ) ) - {} - - - void qc_database::open( const std::function&, - const vector& )>& validator ) - { - if (!fc::is_directory(my->datadir)) - fc::create_directories(my->datadir); - - auto qc_db_dat = my->datadir / config::qcdb_filename; - if( fc::exists( qc_db_dat ) ) { - try { - //string content; - //fc::read_file_contents( qc_db_dat, content ); - - //fc::datastream ds( content.data(), content.size() ); - - // validate totem - //uint32_t totem = 0; - //fc::raw::unpack( ds, totem ); - /*EOS_ASSERT( totem == magic_number, fork_database_exception, - "Fork database file '${filename}' has unexpected magic number: ${actual_totem}. Expected ${expected_totem}", - ("filename", fork_db_dat.generic_string()) - ("actual_totem", totem) - ("expected_totem", magic_number) - );*/ - - // validate version - //uint32_t version = 0; - //fc::raw::unpack( ds, version ); - /*EOS_ASSERT( version >= min_supported_version && version <= max_supported_version, - fork_database_exception, - "Unsupported version of fork database file '${filename}'. " - "Fork database version is ${version} while code supports version(s) [${min},${max}]", - ("filename", fork_db_dat.generic_string()) - ("version", version) - ("min", min_supported_version) - ("max", max_supported_version) - );*/ - - /*block_header_state bhs; - fc::raw::unpack( ds, bhs ); - reset( bhs ); - - unsigned_int size; fc::raw::unpack( ds, size ); - for( uint32_t i = 0, n = size.value; i < n; ++i ) { - block_state s; - fc::raw::unpack( ds, s ); - // do not populate transaction_metadatas, they will be created as needed in apply_block with appropriate key recovery - s.header_exts = s.block->validate_and_extract_header_extensions(); - my->add( std::make_shared( move( s ) ), false, true, validator ); - } - block_id_type head_id; - fc::raw::unpack( ds, head_id ); - - if( my->root->id == head_id ) { - my->head = my->root; - } else { - my->head = get_block( head_id ); - EOS_ASSERT( my->head, fork_database_exception, - "could not find head while reconstructing fork database from file; '${filename}' is likely corrupted", - ("filename", fork_db_dat.generic_string()) ); - } - - auto candidate = my->index.get().begin(); - if( candidate == my->index.get().end() || !(*candidate)->is_valid() ) { - EOS_ASSERT( my->head->id == my->root->id, fork_database_exception, - "head not set to root despite no better option available; '${filename}' is likely corrupted", - ("filename", fork_db_dat.generic_string()) ); - } else { - EOS_ASSERT( !first_preferred( **candidate, *my->head ), fork_database_exception, - "head not set to best available option available; '${filename}' is likely corrupted", - ("filename", fork_db_dat.generic_string()) ); - }*/ - } FC_CAPTURE_AND_RETHROW( (qc_db_dat) ) - - fc::remove( qc_db_dat ); - } - } - - void qc_database::close() { - auto qc_db_dat = my->datadir / config::qcdb_filename; - -/* if( !my->root ) { - if( my->index.size() > 0 ) { - elog( "fork_database is in a bad state when closing; not writing out '${filename}'", - ("filename", fork_db_dat.generic_string()) ); - } - return; - }*/ - - /*std::ofstream out( fork_db_dat.generic_string().c_str(), std::ios::out | std::ios::binary | std::ofstream::trunc ); - fc::raw::pack( out, magic_number ); - fc::raw::pack( out, max_supported_version ); // write out current version which is always max_supported_version - fc::raw::pack( out, *static_cast(&*my->root) ); - uint32_t num_blocks_in_fork_db = my->index.size(); - fc::raw::pack( out, unsigned_int{num_blocks_in_fork_db} ); - - const auto& indx = my->index.get(); - - auto unvalidated_itr = indx.rbegin(); - auto unvalidated_end = boost::make_reverse_iterator( indx.lower_bound( false ) ); - - auto validated_itr = unvalidated_end; - auto validated_end = indx.rend(); - - for( bool unvalidated_remaining = (unvalidated_itr != unvalidated_end), - validated_remaining = (validated_itr != validated_end); - - unvalidated_remaining || validated_remaining; - - unvalidated_remaining = (unvalidated_itr != unvalidated_end), - validated_remaining = (validated_itr != validated_end) - ) - { - auto itr = (validated_remaining ? validated_itr : unvalidated_itr); - - if( unvalidated_remaining && validated_remaining ) { - if( first_preferred( **validated_itr, **unvalidated_itr ) ) { - itr = unvalidated_itr; - ++unvalidated_itr; - } else { - ++validated_itr; - } - } else if( unvalidated_remaining ) { - ++unvalidated_itr; - } else { - ++validated_itr; - } - - fc::raw::pack( out, *(*itr) ); - } - - if( my->head ) { - fc::raw::pack( out, my->head->id ); - } else { - elog( "head not set in fork database; '${filename}' will be corrupted", - ("filename", fork_db_dat.generic_string()) ); - } - - my->index.clear();*/ - } - - qc_database::~qc_database() { - close(); - } - - /*void fork_database::reset( const block_header_state& root_bhs ) { - my->index.clear(); - my->root = std::make_shared(); - static_cast(*my->root) = root_bhs; - my->root->validated = true; - my->head = my->root; - } - - void fork_database::rollback_head_to_root() { - auto& by_id_idx = my->index.get(); - auto itr = by_id_idx.begin(); - while (itr != by_id_idx.end()) { - by_id_idx.modify( itr, [&]( block_state_ptr& bsp ) { - bsp->validated = false; - } ); - ++itr; - } - my->head = my->root; - }*/ - - /*void fork_database::advance_root( const block_id_type& id ) { - EOS_ASSERT( my->root, fork_database_exception, "root not yet set" ); - - auto new_root = get_block( id ); - EOS_ASSERT( new_root, fork_database_exception, - "cannot advance root to a block that does not exist in the fork database" ); - EOS_ASSERT( new_root->is_valid(), fork_database_exception, - "cannot advance root to a block that has not yet been validated" ); - - - deque blocks_to_remove; - for( auto b = new_root; b; ) { - blocks_to_remove.emplace_back( b->header.previous ); - b = get_block( blocks_to_remove.back() ); - EOS_ASSERT( b || blocks_to_remove.back() == my->root->id, fork_database_exception, "invariant violation: orphaned branch was present in forked database" ); - } - - // The new root block should be erased from the fork database index individually rather than with the remove method, - // because we do not want the blocks branching off of it to be removed from the fork database. - my->index.erase( my->index.find( id ) ); - - // The other blocks to be removed are removed using the remove method so that orphaned branches do not remain in the fork database. - for( const auto& block_id : blocks_to_remove ) { - remove( block_id ); - } - - // Even though fork database no longer needs block or trxs when a block state becomes a root of the tree, - // avoid mutating the block state at all, for example clearing the block shared pointer, because other - // parts of the code which run asynchronously may later expect it remain unmodified. - - my->root = new_root; - }*/ - - /*block_header_state_ptr fork_database::get_block_header( const block_id_type& id )const { - if( my->root->id == id ) { - return my->root; - } - - auto itr = my->index.find( id ); - if( itr != my->index.end() ) - return *itr; - - return block_header_state_ptr(); - }*/ - - /*void fork_database_impl::add( const block_state_ptr& n, - bool ignore_duplicate, bool validate, - const std::function&, - const vector& )>& validator ) - { - EOS_ASSERT( root, fork_database_exception, "root not yet set" ); - EOS_ASSERT( n, fork_database_exception, "attempt to add null block state" ); - - auto prev_bh = self.get_block_header( n->header.previous ); - - EOS_ASSERT( prev_bh, unlinkable_block_exception, - "unlinkable block", ("id", n->id)("previous", n->header.previous) ); - - if( validate ) { - try { - const auto& exts = n->header_exts; - - if( exts.count(protocol_feature_activation::extension_id()) > 0 ) { - const auto& new_protocol_features = std::get(exts.lower_bound(protocol_feature_activation::extension_id())->second).protocol_features; - validator( n->header.timestamp, prev_bh->activated_protocol_features->protocol_features, new_protocol_features ); - } - } EOS_RETHROW_EXCEPTIONS( fork_database_exception, "serialized fork database is incompatible with configured protocol features" ) - } - - auto inserted = index.insert(n); - if( !inserted.second ) { - if( ignore_duplicate ) return; - EOS_THROW( fork_database_exception, "duplicate block added", ("id", n->id) ); - } - - auto candidate = index.get().begin(); - if( (*candidate)->is_valid() ) { - head = *candidate; - } - }*/ - - /*void fork_database::add( const block_state_ptr& n, bool ignore_duplicate ) { - my->add( n, ignore_duplicate, false, - []( block_timestamp_type timestamp, - const flat_set& cur_features, - const vector& new_features ) - {} - ); - }*/ - - /*const block_state_ptr& fork_database::root()const { return my->root; } - - const block_state_ptr& fork_database::head()const { return my->head; } - - block_state_ptr fork_database::pending_head()const { - const auto& indx = my->index.get(); - - auto itr = indx.lower_bound( false ); - if( itr != indx.end() && !(*itr)->is_valid() ) { - if( first_preferred( **itr, *my->head ) ) - return *itr; - } - - return my->head; - } - - branch_type fork_database::fetch_branch( const block_id_type& h, uint32_t trim_after_block_num )const { - branch_type result; - for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) { - if( s->block_num <= trim_after_block_num ) - result.push_back( s ); - } - - return result; - } - - block_state_ptr fork_database::search_on_branch( const block_id_type& h, uint32_t block_num )const { - for( auto s = get_block(h); s; s = get_block( s->header.previous ) ) { - if( s->block_num == block_num ) - return s; - } - - return {}; - }*/ - - /** - * Given two head blocks, return two branches of the fork graph that - * end with a common ancestor (same prior block) - */ - /*pair< branch_type, branch_type > fork_database::fetch_branch_from( const block_id_type& first, - const block_id_type& second )const { - pair result; - auto first_branch = (first == my->root->id) ? my->root : get_block(first); - auto second_branch = (second == my->root->id) ? my->root : get_block(second); - - EOS_ASSERT(first_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", first)); - EOS_ASSERT(second_branch, fork_db_block_not_found, "block ${id} does not exist", ("id", second)); - - while( first_branch->block_num > second_branch->block_num ) - { - result.first.push_back(first_branch); - const auto& prev = first_branch->header.previous; - first_branch = (prev == my->root->id) ? my->root : get_block( prev ); - EOS_ASSERT( first_branch, fork_db_block_not_found, - "block ${id} does not exist", - ("id", prev) - ); - } - - while( second_branch->block_num > first_branch->block_num ) - { - result.second.push_back( second_branch ); - const auto& prev = second_branch->header.previous; - second_branch = (prev == my->root->id) ? my->root : get_block( prev ); - EOS_ASSERT( second_branch, fork_db_block_not_found, - "block ${id} does not exist", - ("id", prev) - ); - } - - if (first_branch->id == second_branch->id) return result; - - while( first_branch->header.previous != second_branch->header.previous ) - { - result.first.push_back(first_branch); - result.second.push_back(second_branch); - const auto &first_prev = first_branch->header.previous; - first_branch = get_block( first_prev ); - const auto &second_prev = second_branch->header.previous; - second_branch = get_block( second_prev ); - EOS_ASSERT( first_branch, fork_db_block_not_found, - "block ${id} does not exist", - ("id", first_prev) - ); - EOS_ASSERT( second_branch, fork_db_block_not_found, - "block ${id} does not exist", - ("id", second_prev) - ); - } - - if( first_branch && second_branch ) - { - result.first.push_back(first_branch); - result.second.push_back(second_branch); - } - return result; - } /// fetch_branch_from - - /// remove all of the invalid forks built off of this id including this id - void fork_database::remove( const block_id_type& id ) { - deque remove_queue{id}; - const auto& previdx = my->index.get(); - const auto& head_id = my->head->id; - - for( uint32_t i = 0; i < remove_queue.size(); ++i ) { - EOS_ASSERT( remove_queue[i] != head_id, fork_database_exception, - "removing the block and its descendants would remove the current head block" ); - - auto previtr = previdx.lower_bound( remove_queue[i] ); - while( previtr != previdx.end() && (*previtr)->header.previous == remove_queue[i] ) { - remove_queue.emplace_back( (*previtr)->id ); - ++previtr; - } - } - - for( const auto& block_id : remove_queue ) { - auto itr = my->index.find( block_id ); - if( itr != my->index.end() ) - my->index.erase(itr); - } - } - - void fork_database::mark_valid( const block_state_ptr& h ) { - if( h->validated ) return; - - auto& by_id_idx = my->index.get(); - - auto itr = by_id_idx.find( h->id ); - EOS_ASSERT( itr != by_id_idx.end(), fork_database_exception, - "block state not in fork database; cannot mark as valid", - ("id", h->id) ); - - by_id_idx.modify( itr, []( block_state_ptr& bsp ) { - bsp->validated = true; - } ); - - auto candidate = my->index.get().begin(); - if( first_preferred( **candidate, *my->head ) ) { - my->head = *candidate; - } - } - - block_state_ptr fork_database::get_block(const block_id_type& id)const { - auto itr = my->index.find( id ); - if( itr != my->index.end() ) - return *itr; - return block_state_ptr(); - }*/ - -} } /// eosio::chain diff --git a/libraries/chain/webassembly/crypto.cpp b/libraries/chain/webassembly/crypto.cpp index 9fa4d0bf63..606ca383e7 100644 --- a/libraries/chain/webassembly/crypto.cpp +++ b/libraries/chain/webassembly/crypto.cpp @@ -7,8 +7,6 @@ #include #include #include -#undef g1_add -#include #include #include @@ -120,8 +118,6 @@ namespace eosio { namespace chain { namespace webassembly { *hash_val = context.trx_context.hash_with_checktime( data.data(), data.size() ); } -#undef g1_add - int32_t interface::alt_bn128_add(span op1, span op2, span result ) const { if (op1.size() != 64 || op2.size() != 64 || result.size() < 64 || bn256::g1_add(std::span{(const uint8_t*)op1.data(), 64}, diff --git a/libraries/hotstuff/CMakeLists.txt b/libraries/hotstuff/CMakeLists.txt index b241f56440..0a2a7c6b06 100644 --- a/libraries/hotstuff/CMakeLists.txt +++ b/libraries/hotstuff/CMakeLists.txt @@ -1,7 +1,6 @@ file(GLOB HEADERS "include/eosio/hotstuff/*.hpp") add_library( hotstuff - test_pacemaker.cpp chain_pacemaker.cpp qc_chain.cpp ${HEADERS} diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 92b04e7693..7ca5bdd50b 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -117,7 +117,7 @@ namespace eosio { namespace hotstuff { _qc_chain.get_state( fs ); // get_state() takes scare of finer-grained synchronization internally } - name chain_pacemaker::get_proposer(){ + name chain_pacemaker::get_proposer() { const block_state_ptr& hbs = _chain->head_block_state(); name n = hbs->header.producer; return n; @@ -188,7 +188,7 @@ namespace eosio { namespace hotstuff { return n; } - name chain_pacemaker::get_leader(){ + name chain_pacemaker::get_leader() { const block_state_ptr& hbs = _chain->head_block_state(); name n = hbs->header.producer; @@ -198,7 +198,7 @@ namespace eosio { namespace hotstuff { return n; } - name chain_pacemaker::get_next_leader(){ + name chain_pacemaker::get_next_leader() { const block_state_ptr& hbs = _chain->head_block_state(); block_timestamp_type next_block_time = hbs->header.timestamp.next(); producer_authority p_auth = hbs->get_scheduled_producer(next_block_time); @@ -210,27 +210,26 @@ namespace eosio { namespace hotstuff { return n; } - std::vector chain_pacemaker::get_finalizers(){ + std::vector chain_pacemaker::get_finalizers() { const block_state_ptr& hbs = _chain->head_block_state(); - std::vector pa_list = hbs->active_schedule.producers; + const std::vector& pa_list = hbs->active_schedule.producers; std::vector pn_list; + pn_list.reserve(pa_list.size()); std::transform(pa_list.begin(), pa_list.end(), std::back_inserter(pn_list), [](const producer_authority& p) { return p.producer_name; }); return pn_list; } - block_id_type chain_pacemaker::get_current_block_id(){ - block_header header = _chain->head_block_state()->header; - block_id_type block_id = header.calculate_id(); - return block_id; + block_id_type chain_pacemaker::get_current_block_id() { + return _chain->head_block_id(); } - uint32_t chain_pacemaker::get_quorum_threshold(){ + uint32_t chain_pacemaker::get_quorum_threshold() { return _quorum_threshold; } - void chain_pacemaker::beat(){ + void chain_pacemaker::beat() { if (! enabled()) return; @@ -241,27 +240,27 @@ namespace eosio { namespace hotstuff { prof.core_out(); } - void chain_pacemaker::send_hs_proposal_msg(const hs_proposal_message & msg, name id){ + void chain_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, name id) { hs_proposal_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_proposal_msg(msg_ptr); } - void chain_pacemaker::send_hs_vote_msg(const hs_vote_message & msg, name id){ + void chain_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, name id) { hs_vote_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_vote_msg(msg_ptr); } - void chain_pacemaker::send_hs_new_block_msg(const hs_new_block_message & msg, name id){ + void chain_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, name id) { hs_new_block_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_new_block_msg(msg_ptr); } - void chain_pacemaker::send_hs_new_view_msg(const hs_new_view_message & msg, name id){ + void chain_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, name id) { hs_new_view_message_ptr msg_ptr = std::make_shared(msg); _chain->commit_hs_new_view_msg(msg_ptr); } - void chain_pacemaker::on_hs_proposal_msg(const hs_proposal_message & msg){ + void chain_pacemaker::on_hs_proposal_msg(const hs_proposal_message& msg) { if (! enabled()) return; @@ -272,7 +271,7 @@ namespace eosio { namespace hotstuff { prof.core_out(); } - void chain_pacemaker::on_hs_vote_msg(const hs_vote_message & msg){ + void chain_pacemaker::on_hs_vote_msg(const hs_vote_message& msg) { if (! enabled()) return; @@ -283,7 +282,7 @@ namespace eosio { namespace hotstuff { prof.core_out(); } - void chain_pacemaker::on_hs_new_block_msg(const hs_new_block_message & msg){ + void chain_pacemaker::on_hs_new_block_msg(const hs_new_block_message& msg) { if (! enabled()) return; @@ -294,7 +293,7 @@ namespace eosio { namespace hotstuff { prof.core_out(); } - void chain_pacemaker::on_hs_new_view_msg(const hs_new_view_message & msg){ + void chain_pacemaker::on_hs_new_view_msg(const hs_new_view_message& msg) { if (! enabled()) return; diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index 9d172360d5..7b264b28dc 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -1,16 +1,18 @@ #pragma once -#include -//#include +#include #include -#include -#include -using namespace eosio::chain; +#include -namespace eosio { namespace hotstuff { +namespace eosio::chain { + struct hs_proposal_message; + struct hs_vote_message; + struct hs_new_view_message; + struct hs_new_block_message; +} - class qc_chain; +namespace eosio::hotstuff { // Abstract pacemaker; a reference of this type will only be used by qc_chain, as qc_chain // cannot know which environment it is in. @@ -23,21 +25,23 @@ namespace eosio { namespace hotstuff { virtual ~base_pacemaker() = default; //TODO: discuss +#warning discuss virtual uint32_t get_quorum_threshold() = 0; - virtual block_id_type get_current_block_id() = 0; + virtual chain::block_id_type get_current_block_id() = 0; //hotstuff getters. todo : implement relevant setters as host functions - virtual name get_proposer() = 0; - virtual name get_leader() = 0; - virtual name get_next_leader() = 0; - virtual std::vector get_finalizers() = 0; +#warning hotstuff getters. todo : implement relevant setters as host functions + virtual chain::name get_proposer() = 0; + virtual chain::name get_leader() = 0; + virtual chain::name get_next_leader() = 0; + virtual std::vector get_finalizers() = 0; //outbound communications; 'id' is the producer name (can be ignored if/when irrelevant to the implementer) - virtual void send_hs_proposal_msg(const hs_proposal_message& msg, name id) = 0; - virtual void send_hs_vote_msg(const hs_vote_message& msg, name id) = 0; - virtual void send_hs_new_view_msg(const hs_new_view_message& msg, name id) = 0; - virtual void send_hs_new_block_msg(const hs_new_block_message& msg, name id) = 0; + virtual void send_hs_proposal_msg(const chain::hs_proposal_message& msg, chain::name id) = 0; + virtual void send_hs_vote_msg(const chain::hs_vote_message& msg, chain::name id) = 0; + virtual void send_hs_new_view_msg(const chain::hs_new_view_message& msg, chain::name id) = 0; + virtual void send_hs_new_block_msg(const chain::hs_new_block_message& msg, chain::name id) = 0; }; -}} +} // namespace eosio::hotstuff diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index be53d83fcf..02e2aff59b 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -1,12 +1,13 @@ #pragma once #include - -#include - #include -namespace eosio { namespace hotstuff { +namespace eosio::chain { + class controller; +} + +namespace eosio::hotstuff { class chain_pacemaker : public base_pacemaker { public: @@ -52,6 +53,7 @@ namespace eosio { namespace hotstuff { // For maximum safety, the qc_chain core will only process one request at a time. // These requests can come directly from the net threads, or indirectly from a // dedicated finalizer thread (TODO: discuss). +#warning discuss std::mutex _hotstuff_global_mutex; chain::controller* _chain = nullptr; @@ -61,4 +63,4 @@ namespace eosio { namespace hotstuff { uint32_t _quorum_threshold = 15; //FIXME/TODO: calculate from schedule }; -}} +} // namespace eosio::hotstuff diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 336ad61bb7..0a59c0dcb3 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -1,11 +1,12 @@ #pragma once #include -//#include #include #include #include #include + #include +#include #include #include @@ -20,12 +21,11 @@ #include #include -#include // Enable this to swap the multi-index proposal store with std::map //#define QC_CHAIN_SIMPLE_PROPOSAL_STORE -namespace eosio { namespace hotstuff { +namespace eosio::hotstuff { using boost::multi_index_container; using namespace boost::multi_index; @@ -38,6 +38,7 @@ namespace eosio { namespace hotstuff { qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, bool info_logging, bool error_logging); +#warning remove. bls12-381 key used for testing purposes //todo : remove. bls12-381 key used for testing purposes std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, @@ -82,10 +83,10 @@ namespace eosio { namespace hotstuff { bool _errors = true; // returns nullptr if not found - const hs_proposal_message* get_proposal(fc::sha256 proposal_id); + const hs_proposal_message* get_proposal(const fc::sha256& proposal_id); // returns false if proposal with that same ID already exists at the store of its height - bool insert_proposal(const hs_proposal_message & proposal); + bool insert_proposal(const hs_proposal_message& proposal); void get_state( finalizer_state& fs ) const; @@ -93,55 +94,53 @@ namespace eosio { namespace hotstuff { fc::unsigned_int update_bitset(fc::unsigned_int value, name finalizer); - digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc); //get digest to sign from proposal data + digest_type get_digest_to_sign(const block_id_type& block_id, uint8_t phase_counter, const fc::sha256& final_on_qc); //get digest to sign from proposal data - void reset_qc(fc::sha256 proposal_id); //reset current internal qc + void reset_qc(const fc::sha256& proposal_id); //reset current internal qc - bool evaluate_quorum(const extended_schedule & es, fc::unsigned_int finalizers, const fc::crypto::blslib::bls_signature & agg_sig, const hs_proposal_message & proposal); //evaluate quorum for a proposal + bool evaluate_quorum(const extended_schedule& es, fc::unsigned_int finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal // qc.quorum_met has to be updated by the caller (if it wants to) based on the return value of this method - bool is_quorum_met(const eosio::chain::quorum_certificate & qc, const extended_schedule & schedule, const hs_proposal_message & proposal); //check if quorum has been met over a proposal + bool is_quorum_met(const eosio::chain::quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal); //check if quorum has been met over a proposal - std::vector get_finalizers(); //get current finalizers set - - hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); //create new proposal message - hs_new_block_message new_block_candidate(block_id_type block_id); //create new block message + hs_proposal_message new_proposal_candidate(const block_id_type& block_id, uint8_t phase_counter); //create new proposal message + hs_new_block_message new_block_candidate(const block_id_type& block_id); //create new block message bool am_i_proposer(); //check if I am the current proposer bool am_i_leader(); //check if I am the current leader bool am_i_finalizer(); //check if I am one of the current finalizers - void process_proposal(const hs_proposal_message & msg); //handles proposal - void process_vote(const hs_vote_message & msg); //handles vote - void process_new_view(const hs_new_view_message & msg); //handles new view - void process_new_block(const hs_new_block_message & msg); //handles new block + void process_proposal(const hs_proposal_message& msg); //handles proposal + void process_vote(const hs_vote_message& msg); //handles vote + void process_new_view(const hs_new_view_message& msg); //handles new view + void process_new_block(const hs_new_block_message& msg); //handles new block - hs_vote_message sign_proposal(const hs_proposal_message & proposal, name finalizer); //sign proposal + hs_vote_message sign_proposal(const hs_proposal_message& proposal, name finalizer); //sign proposal - bool extends(fc::sha256 descendant, fc::sha256 ancestor); //verify that a proposal descends from another + bool extends(const fc::sha256& descendant, const fc::sha256& ancestor); //verify that a proposal descends from another void on_beat(); //handler for pacemaker beat() - void update_high_qc(const eosio::chain::quorum_certificate & high_qc); //check if update to our high qc is required + void update_high_qc(const eosio::chain::quorum_certificate& high_qc); //check if update to our high qc is required void leader_rotation_check(); //check if leader rotation is required - bool is_node_safe(const hs_proposal_message & proposal); //verify if a proposal should be signed + bool is_node_safe(const hs_proposal_message& proposal); //verify if a proposal should be signed - std::vector get_qc_chain(fc::sha256 proposal_id); //get 3-phase proposal justification + std::vector get_qc_chain(const fc::sha256& proposal_id); //get 3-phase proposal justification - void send_hs_proposal_msg(const hs_proposal_message & msg); //send vote msg - void send_hs_vote_msg(const hs_vote_message & msg); //send proposal msg - void send_hs_new_view_msg(const hs_new_view_message & msg); //send new view msg - void send_hs_new_block_msg(const hs_new_block_message & msg); //send new block msg + void send_hs_proposal_msg(const hs_proposal_message& msg); //send vote msg + void send_hs_vote_msg(const hs_vote_message& msg); //send proposal msg + void send_hs_new_view_msg(const hs_new_view_message& msg); //send new view msg + void send_hs_new_block_msg(const hs_new_block_message& msg); //send new block msg - void on_hs_vote_msg(const hs_vote_message & msg); //vote msg event handler - void on_hs_proposal_msg(const hs_proposal_message & msg); //proposal msg event handler - void on_hs_new_view_msg(const hs_new_view_message & msg); //new view msg event handler - void on_hs_new_block_msg(const hs_new_block_message & msg); //new block msg event handler + void on_hs_vote_msg(const hs_vote_message& msg); //vote msg event handler + void on_hs_proposal_msg(const hs_proposal_message& msg); //proposal msg event handler + void on_hs_new_view_msg(const hs_new_view_message& msg); //new view msg event handler + void on_hs_new_block_msg(const hs_new_block_message& msg); //new block msg event handler - void update(const hs_proposal_message & proposal); //update internal state - void commit(const hs_proposal_message & proposal); //commit proposal (finality) + void update(const hs_proposal_message& proposal); //update internal state + void commit(const hs_proposal_message& proposal); //commit proposal (finality) void gc_proposals(uint64_t cutoff); //garbage collection of old proposals @@ -193,4 +192,5 @@ namespace eosio { namespace hotstuff { #endif }; -}} /// eosio::qc_chain + +} /// eosio::hotstuff diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index 1b60e171f0..567eb44465 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -83,7 +83,7 @@ namespace eosio { namespace hotstuff { block_id_type _current_block_id; std::vector _unique_replicas; - +#warning calculate from schedule uint32_t _quorum_threshold = 15; //todo : calculate from schedule }; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 3bab42d27d..22e5e6d1f2 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -49,7 +49,7 @@ namespace eosio { namespace hotstuff { - const hs_proposal_message* qc_chain::get_proposal(fc::sha256 proposal_id) { + const hs_proposal_message* qc_chain::get_proposal(const fc::sha256& proposal_id) { #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE if (proposal_id == NULL_PROPOSAL_ID) return nullptr; @@ -173,13 +173,13 @@ namespace eosio { namespace hotstuff { throw std::runtime_error("qc_chain internal error: finalizer not found"); } - digest_type qc_chain::get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ + digest_type qc_chain::get_digest_to_sign(const block_id_type& block_id, uint8_t phase_counter, const fc::sha256& final_on_qc){ digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); return h2; } - std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id) { + std::vector qc_chain::get_qc_chain(const fc::sha256& proposal_id) { std::vector ret_arr; const hs_proposal_message *b, *b1, *b2; b2 = get_proposal( proposal_id ); @@ -196,7 +196,7 @@ namespace eosio { namespace hotstuff { return ret_arr; } - hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { + hs_proposal_message qc_chain::new_proposal_candidate(const block_id_type& block_id, uint8_t phase_counter) { hs_proposal_message b_new; b_new.block_id = block_id; b_new.parent_id = _b_leaf; @@ -237,7 +237,7 @@ namespace eosio { namespace hotstuff { return b_new; } - void qc_chain::reset_qc(fc::sha256 proposal_id){ + void qc_chain::reset_qc(const fc::sha256& proposal_id){ std::lock_guard g( _state_mutex ); #ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); @@ -248,7 +248,7 @@ namespace eosio { namespace hotstuff { _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); } - hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { + hs_new_block_message qc_chain::new_block_candidate(const block_id_type& block_id) { hs_new_block_message b; b.block_id = block_id; b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch @@ -276,7 +276,7 @@ namespace eosio { namespace hotstuff { else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); } } - +#warning fix todo // **************************************************************************************************** // FIXME/TODO: I removed this since it doesn't seem to be doing anything at the moment // **************************************************************************************************** @@ -355,7 +355,7 @@ namespace eosio { namespace hotstuff { digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); std::vector h = std::vector(digest.data(), digest.data() + 32); - +#warning use appropriate private key for each producer fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //FIXME/TODO: use appropriate private key for each producer hs_vote_message v_msg = {proposal.proposal_id, finalizer, sig}; @@ -504,7 +504,7 @@ namespace eosio { namespace hotstuff { void qc_chain::process_vote(const hs_vote_message & vote){ //auto start = fc::time_point::now(); - +#warning check for duplicate or invalid vote. We will return in either case, but keep proposals for evidence of double signing //TODO: check for duplicate or invalid vote. We will return in either case, but keep proposals for evidence of double signing bool am_leader = am_i_leader(); @@ -602,6 +602,7 @@ namespace eosio { namespace hotstuff { void qc_chain::process_new_block(const hs_new_block_message & msg){ // If I'm not a leader, I probably don't care about hs-new-block messages. +#warning check for a need to gossip/rebroadcast even if it's not for us (maybe here, maybe somewhere else). // TODO: check for a need to gossip/rebroadcast even if it's not for us (maybe here, maybe somewhere else). if (! am_i_leader()) { @@ -615,6 +616,7 @@ namespace eosio { namespace hotstuff { if (_log) ilog(" === ${id} process_new_block === am leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); #endif +#warning What to do with the received msg.justify? // ------------------------------------------------------------------ // // FIXME/REVIEW/TODO: What to do with the received msg.justify? @@ -697,8 +699,9 @@ namespace eosio { namespace hotstuff { } //extends predicate - bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ + bool qc_chain::extends(const fc::sha256& descendant, const fc::sha256& ancestor){ +#warning confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified //TODO: confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified uint32_t counter = 0; diff --git a/libraries/hotstuff/test/CMakeLists.txt b/libraries/hotstuff/test/CMakeLists.txt index 8ef773c64a..b147f10496 100644 --- a/libraries/hotstuff/test/CMakeLists.txt +++ b/libraries/hotstuff/test/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable( test_hotstuff test_hotstuff.cpp) +add_executable( test_hotstuff test_hotstuff.cpp test_pacemaker.cpp) target_link_libraries( test_hotstuff hotstuff fc Boost::unit_test_framework) add_test(NAME test_hotstuff COMMAND test_hotstuff WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) diff --git a/libraries/hotstuff/test/Testing/Temporary/CTestCostData.txt b/libraries/hotstuff/test/Testing/Temporary/CTestCostData.txt deleted file mode 100644 index ed97d539c0..0000000000 --- a/libraries/hotstuff/test/Testing/Temporary/CTestCostData.txt +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/libraries/hotstuff/test/Testing/Temporary/LastTest.log b/libraries/hotstuff/test/Testing/Temporary/LastTest.log deleted file mode 100644 index a144c6eee8..0000000000 --- a/libraries/hotstuff/test/Testing/Temporary/LastTest.log +++ /dev/null @@ -1,3 +0,0 @@ -Start testing: Mar 09 14:59 UTC ----------------------------------------------------------- -End testing: Mar 09 14:59 UTC diff --git a/libraries/hotstuff/test_pacemaker.cpp b/libraries/hotstuff/test/test_pacemaker.cpp similarity index 90% rename from libraries/hotstuff/test_pacemaker.cpp rename to libraries/hotstuff/test/test_pacemaker.cpp index ddf91b6306..ff21284a6f 100644 --- a/libraries/hotstuff/test_pacemaker.cpp +++ b/libraries/hotstuff/test/test_pacemaker.cpp @@ -1,7 +1,7 @@ #include #include -namespace eosio { namespace hotstuff { +namespace eosio::hotstuff { void test_pacemaker::set_proposer(name proposer) { _proposer = proposer; @@ -93,11 +93,11 @@ namespace eosio { namespace hotstuff { ilog(" === ${memo} : ", ("memo", memo)); } - //ilog(" === pacemaker dispatched ${proposals} proposals, ${votes} votes, ${new_blocks} new_blocks, ${new_views} new_views", - // ("proposals", proposals_count) - // ("votes", votes_count) - // ("new_blocks", new_blocks_count) - // ("new_views", new_views_count)); + ilog(" === pacemaker dispatched ${proposals} proposals, ${votes} votes, ${new_blocks} new_blocks, ${new_views} new_views", + ("proposals", proposals_count) + ("votes", votes_count) + ("new_blocks", new_blocks_count) + ("new_views", new_views_count)); return dispatched_messages; } @@ -158,23 +158,23 @@ namespace eosio { namespace hotstuff { _qcc_store.emplace( name, qcc_ptr ); }; - void test_pacemaker::send_hs_proposal_msg(const hs_proposal_message & msg, name id) { + void test_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, name id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_vote_msg(const hs_vote_message & msg, name id) { + void test_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, name id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_block_msg(const hs_new_block_message & msg, name id) { + void test_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, name id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_view_msg(const hs_new_view_message & msg, name id) { + void test_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, name id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::on_hs_proposal_msg(const hs_proposal_message & msg, name id) { + void test_pacemaker::on_hs_proposal_msg(const hs_proposal_message& msg, name id) { auto qc_itr = _qcc_store.begin(); while (qc_itr != _qcc_store.end()){ const name & qcc_name = qc_itr->first; @@ -185,7 +185,7 @@ namespace eosio { namespace hotstuff { } } - void test_pacemaker::on_hs_vote_msg(const hs_vote_message & msg, name id) { + void test_pacemaker::on_hs_vote_msg(const hs_vote_message& msg, name id) { auto qc_itr = _qcc_store.begin(); while (qc_itr != _qcc_store.end()) { const name & qcc_name = qc_itr->first; @@ -196,7 +196,7 @@ namespace eosio { namespace hotstuff { } } - void test_pacemaker::on_hs_new_block_msg(const hs_new_block_message & msg, name id) { + void test_pacemaker::on_hs_new_block_msg(const hs_new_block_message& msg, name id) { auto qc_itr = _qcc_store.begin(); while (qc_itr != _qcc_store.end()) { const name & qcc_name = qc_itr->first; @@ -207,7 +207,7 @@ namespace eosio { namespace hotstuff { } } - void test_pacemaker::on_hs_new_view_msg(const hs_new_view_message & msg, name id) { + void test_pacemaker::on_hs_new_view_msg(const hs_new_view_message& msg, name id) { auto qc_itr = _qcc_store.begin(); while (qc_itr != _qcc_store.end()){ const name & qcc_name = qc_itr->first; @@ -218,4 +218,4 @@ namespace eosio { namespace hotstuff { } } -}} +} // namespace eosio::hotstuff diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index a5894951ab..c9a9feb6dd 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -843,7 +843,7 @@ class read_only : public api_base { uint8_t phase_counter = 0; uint32_t block_height = 0; uint64_t view_number = 0; - hs_complete_proposal_message( const chain::hs_proposal_message & p ) { + explicit hs_complete_proposal_message( const chain::hs_proposal_message & p ) { proposal_id = p.proposal_id; block_id = p.block_id; parent_id = p.parent_id; diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp index 68828062df..f102dfcf0b 100644 --- a/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp +++ b/plugins/producer_plugin/include/eosio/producer_plugin/producer_plugin.hpp @@ -2,7 +2,6 @@ #include #include -#include #include #include diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 4b4eec0f7a..4384c52c56 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include #include @@ -517,7 +516,6 @@ class producer_plugin_impl : public std::enable_shared_from_this _signature_providers; @@ -1043,7 +1041,7 @@ void producer_plugin::set_program_options( boost::program_options::options_description producer_options; producer_options.add_options() - ("enable-stale-production,e", boost::program_options::bool_switch()->notifier([this](bool e){my->_production_enabled = e; my->_enable_stale_production_config = e;}), + ("enable-stale-production,e", boost::program_options::bool_switch()->notifier([this](bool e){my->_production_enabled = e;}), "Enable block production, even if the chain is stale.") ("pause-on-startup,x", boost::program_options::bool_switch()->notifier([this](bool p){my->_pause_production = p;}), "Start this node in a state where production is paused") ("max-transaction-time", bpo::value()->default_value(30), diff --git a/plugins/producer_plugin/qc_chain.cpp.bkp b/plugins/producer_plugin/qc_chain.cpp.bkp deleted file mode 100644 index 29290a3fc2..0000000000 --- a/plugins/producer_plugin/qc_chain.cpp.bkp +++ /dev/null @@ -1,1216 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -#include -#include - -#include - -//todo list / notes : - -/* - - - -fork tests in unittests - - - -network plugin versioning - -handshake_message.network_version - -independant of protocol feature activation - - - -separate library for hotstuff (look at SHIP libray used by state history plugin ) - - -boost tests producer plugin test - - - -regression tests python framework as a base - - - -performance testing - - - - -*/ - - - -// -// complete proposer / leader differentiation -// integration with new bls implementation -// -// hotstuff as a library with its own tests (model on state history plugin + state_history library ) -// -// unit / integration tests -> producer_plugin + fork_tests tests as a model -// -// test deterministic sequence -// -// test non-replica participation -// test finality vioaltion -// test loss of liveness -// -// test split chain -// -// integration with fork_db / LIB overhaul -// -// integration with performance testing -// -// regression testing ci/cd -> python regression tests -// -// add APIs for proof data -// -// add election proposal in block header -// -// map proposers / finalizers / leader to new host functions -// -// support pause / resume producer -// -// keep track of proposals sent to peers -// -// allow syncing of proposals -// -// versioning of net protocol version -// -// protocol feature activation HOTSTUFF_CONSENSUS -// -// system contract update 1 -> allow BPs to register + prove their aggregate pub key. Allow existing BPs to unreg + reg without new aggregate key. Prevent new BPs from registering without proving aggregate pub key -// -// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available -// -// - - -namespace eosio { namespace chain { - using boost::multi_index_container; - using namespace boost::multi_index; - - //todo : remove. bls12-381 key used for testing purposes - std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, - 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, - 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; - - fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); - - enum msg_type { - new_view = 1, - new_block = 2, - qc = 3, - vote = 4 - }; - - uint32_t _v_height; - - bool _chained_mode = false ; - - void handle_eptr(std::exception_ptr eptr){ - try { - if (eptr) { - std::rethrow_exception(eptr); - } - } catch(const std::exception& e) { - ilog("Caught exception ${ex}" , ("ex", e.what())); - std::exit(0); - } - } - - const block_id_type NULL_BLOCK_ID = block_id_type("00"); - const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - -/* const block_header_state_ptr NULL_BLOCK_HEADER_STATE_PTR = block_header_state_ptr(); - const block_state_ptr NULL_BLOCK_STATE_PTR = block_state_ptr();*/ - - fc::sha256 _b_leaf = NULL_PROPOSAL_ID; - fc::sha256 _b_lock = NULL_PROPOSAL_ID; - fc::sha256 _b_exec = NULL_PROPOSAL_ID; - - block_id_type _block_exec = NULL_BLOCK_ID; - - eosio::chain::quorum_certificate _high_qc; - eosio::chain::quorum_certificate _current_qc; - - eosio::chain::extended_schedule _schedule; - - chain_plugin* _chain_plug = nullptr; - std::set _my_producers; - - block_id_type _pending_proposal_block = NULL_BLOCK_ID; - - struct by_proposal_id{}; - struct by_proposal_height{}; - - typedef multi_index_container< - hs_proposal_message, - indexed_by< - hashed_unique< - tag, - BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) - >, - ordered_unique< - tag, - BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) - > - > - > proposal_store_type; - - proposal_store_type _proposal_store; - - - digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ - - digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); - digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); - - return h2; - - } - - std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ - - std::vector ret_arr; - - proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); - - b_2_itr = _proposal_store.get().find( proposal_id ); - if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); - if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); - - if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); - if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); - if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); - - return ret_arr; - - } - - name qc_chain::get_proposer(){ - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - return hbs->header.producer; - - } - - name qc_chain::get_leader(){ - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - return hbs->header.producer; - - } - - - std::vector qc_chain::get_finalizers(){ - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - return hbs->active_schedule.producers; - - } - - hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { - - hs_proposal_message b_new; - - b_new.block_id = block_id; - b_new.parent_id = _b_leaf; - b_new.phase_counter = phase_counter; - - b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - - if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ - - std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - if (chain_length>=2){ - - auto itr = current_qc_chain.begin(); - - hs_proposal_message b2 = *itr; - itr++; - hs_proposal_message b1 = *itr; - - if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; - else { - - proposal_store_type::nth_index<0>::type::iterator p_itr; - - p_itr = _proposal_store.get().find( b1.parent_id ); - - b_new.final_on_qc = p_itr->final_on_qc; - - } - - } - - } - - b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); - - ilog("=== creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", - ("block_num", b_new.block_num()) - ("phase_counter", b_new.phase_counter) - ("proposal_id", b_new.proposal_id) - ("parent_id", b_new.parent_id) - ("justify", b_new.justify.proposal_id)); - - return b_new; - - } - - void reset_qc(fc::sha256 proposal_id){ - - _current_qc.proposal_id = proposal_id; - _current_qc.quorum_met = false; - _current_qc.active_finalizers = {}; - _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); - - } - - hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { - - hs_new_block_message b; - - b.block_id = block_id; - b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - - return b; - } - - bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ -/* -std::exception_ptr eptr; -try{*/ - - if (finalizers.size() < _threshold){ - return false; - } - - fc::crypto::blslib::bls_public_key agg_key; - - for (int i = 0; i < finalizers.size(); i++) { - - //adding finalizer's key to the aggregate pub key - if (i==0) agg_key = _private_key.get_public_key(); - else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); - - } - - fc::crypto::blslib::bls_signature justification_agg_sig; - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; - - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); - - return ok; - -/*} -catch (...){ - ilog("error during evaluate_quorum"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr);*/ - - } - - bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ - -/*std::exception_ptr eptr; -try{ -*/ - if (qc.quorum_met == true ) { - return true; //skip evaluation if we've already verified quorum was met - } - else { - - //ilog("qc : ${qc}", ("qc", qc)); - - bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); - - qc.quorum_met = quorum_met; - - return qc.quorum_met ; - - } -/*} -catch (...){ - ilog("error during find proposals"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr);*/ - } - - void qc_chain::init(chain_plugin& chain_plug, std::set my_producers){ - - _chain_plug = &chain_plug; - _my_producers = my_producers; - - //ilog("qc chain initialized -> my producers : "); - - - } - - block_header_state_ptr qc_chain::get_block_header( const block_id_type& id ){ - - //ilog("get_block_header "); - - chain::controller& chain = _chain_plug->chain(); - - return chain.fork_db().get_block_header(id); - - } - - bool qc_chain::am_i_proposer(){ - - name proposer = get_proposer(); - - //ilog("Proposer : ${proposer}", ("proposer", proposer)); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); - - if (prod_itr==_my_producers.end()) return false; - else return true; - - } - - bool qc_chain::am_i_leader(){ - - name leader = get_leader(); - - //ilog("Leader : ${leader}", ("leader", leader)); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); - - if (prod_itr==_my_producers.end()) return false; - else return true; - - } - - bool qc_chain::am_i_finalizer(){ - - //ilog("am_i_finalizer"); - - std::vector finalizers = get_finalizers(); - - auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); - - if (prod_itr!=finalizers.end()) return true; - - mf_itr++; - - } - - return false; - - } - - void qc_chain::process_proposal(hs_proposal_message proposal){ - - - auto itr = _proposal_store.get().find( proposal.proposal_id ); - - if (itr != _proposal_store.get().end()) { - ilog("*** proposal received twice : ${proposal_id}",("proposal_id", proposal.proposal_id)); - return ; //already aware of proposal, nothing to do - - } - - ilog("=== received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id) - ("parent_id", proposal.parent_id) - ("justify", proposal.justify.proposal_id)); - - _proposal_store.insert(proposal); //new proposal - - bool am_finalizer = am_i_finalizer(); - bool node_safe = is_node_safe(proposal); - - bool signature_required = am_finalizer && node_safe; - - //if I am a finalizer for this proposal, test safenode predicate for possible vote - if (signature_required){ - - //ilog("signature required"); - - _v_height = proposal.get_height(); - - fc::crypto::blslib::bls_signature agg_sig; - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; - - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - //iterate over all my finalizers and sign / broadcast for each that is in the schedule - std::vector finalizers = get_finalizers(); - - //ilog("signed proposal. Broadcasting for each of my producers"); - - auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); - - if (prod_itr!=finalizers.end()) { - - fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer - - hs_vote_message v_msg = {proposal.proposal_id, prod_itr->producer_name, sig}; - - broadcast_hs_vote(v_msg); - - }; - - mf_itr++; - - } - - } - - //update internal state - update(proposal); - - //check for leader change - on_leader_rotate(); - - } - - void qc_chain::process_vote(hs_vote_message vote){ - - //check for duplicate or invalid vote, return in either case - //abstracted [...] - - bool am_leader = am_i_leader(); //am I leader? - - if(!am_leader) return; - - //ilog("=== Process vote from ${finalizer}", ("finalizer", vote.finalizer)); - - //only leader need to take action on votes - - if (vote.proposal_id != _current_qc.proposal_id) return; - - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); - - if (p_itr==_proposal_store.get().end()){ - ilog("*** couldn't find proposal"); - - ilog("*** vote : ${vote}", ("vote", vote)); - - return; - } - - bool quorum_met = _current_qc.quorum_met; //check if quorum already met - - if (!quorum_met){ - - _current_qc.active_finalizers.push_back(vote.finalizer); - - if (_current_qc.active_finalizers.size()>1) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); - else _current_qc.active_agg_sig = vote.sig; - - quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); - - if (quorum_met){ - - _current_qc.quorum_met = true; - - //ilog("=== Quorum met on #${block_num} ${proposal_id} ", ("block_num", p_itr->block_num())("proposal_id", vote.proposal_id)); - - ilog("=== update_high_qc : _current_qc ==="); - update_high_qc(_current_qc); - - //check for leader change - on_leader_rotate(); - - - //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet - if (_chained_mode==false && p_itr->phase_counter<3){ - - hs_proposal_message proposal_candidate; - - if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); - else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); - - reset_qc(proposal_candidate.proposal_id); - - _pending_proposal_block = NULL_BLOCK_ID; - - broadcast_hs_proposal(proposal_candidate); - - _b_leaf = proposal_candidate.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); - - } - - } - - } - - } - - void qc_chain::process_new_view(hs_new_view_message new_view){ - - ilog("=== update_high_qc : process_new_view === ${qc}", ("qc", new_view.high_qc)); - update_high_qc(new_view.high_qc); - - } - - void qc_chain::process_new_block(hs_new_block_message msg){ - - //ilog("=== Process new block ==="); - - } - - void qc_chain::broadcast_hs_proposal(hs_proposal_message msg){ - - //ilog("=== broadcast_hs_proposal ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_proposal_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_proposal_msg(ptr); - - process_proposal(msg); - - } - - - void qc_chain::broadcast_hs_vote(hs_vote_message msg){ - - //ilog("=== broadcast_hs_vote ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_vote_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_vote_msg(ptr); - - process_vote(msg); - - } - - void qc_chain::broadcast_hs_new_view(hs_new_view_message msg){ - - //ilog("=== broadcast_hs_new_view ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_new_view_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_new_view_msg(ptr); - - //process_new_view(msg); //notify ourselves - - } - - void qc_chain::broadcast_hs_new_block(hs_new_block_message msg){ - - //ilog("=== broadcast_hs_new_block ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_new_block_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_new_block_msg(ptr); - - //process_new_block(msg); //notify ourselves - - } - - //extends predicate - bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ - - - //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified - - - proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); - - uint32_t counter = 0; - - while (itr!=_proposal_store.get().end()){ - - itr = _proposal_store.get().find(itr->parent_id ); - - if (itr->proposal_id == ancestor){ - if (counter>25) { - ilog("***"); - ilog("*** took ${counter} iterations to find ancestor ", ("counter", counter)); - ilog("***"); - - } - return true; - } - - counter++; - - } - - ilog(" ***** extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", - ("d_proposal_id", descendant) - ("a_proposal_id", ancestor)); - - return false; - - } - - void qc_chain::on_beat(block_state& hbs){ -std::exception_ptr eptr; -try{ - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - ilog("=== on beat ==="); - - if (hbs.header.producer == "eosio"_n) return ; //if chain has not been activated and doesn't have finalizers, we don't generate proposals - - bool am_proposer = am_i_proposer(); - bool am_leader = am_i_leader(); - - //ilog("=== am_proposer = ${am_proposer}", ("am_proposer", am_proposer)); - //ilog("=== am_leader = ${am_leader}", ("am_leader", am_leader)); - - if (!am_proposer && !am_leader){ - - return; //nothing to do - - } - - //if I am the leader - if (am_leader){ - - //if I'm not also the proposer, perform block validation as required - if (!am_proposer){ - - //todo : extra validation - - } - - - if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ - - _pending_proposal_block = hbs.header.calculate_id(); - - } - else { - - hs_proposal_message proposal_candidate = new_proposal_candidate(hbs.header.calculate_id(), 0 ); - - reset_qc(proposal_candidate.proposal_id); - - _pending_proposal_block = NULL_BLOCK_ID; - - broadcast_hs_proposal(proposal_candidate); - - _b_leaf = proposal_candidate.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); - - } - - } - else { - - //if I'm only a proposer and not the leader, I send a new block message - - hs_new_block_message block_candidate = new_block_candidate(hbs.header.calculate_id()); - - //ilog("=== broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); - - broadcast_hs_new_block(block_candidate); - - } - - //ilog(" === end of on_beat"); -} -catch (...){ - ilog("error during on_beat"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ - - ilog("=== check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); - - // if new high QC is higher than current, update to new - - - if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ - - _high_qc = high_qc; - _b_leaf = _high_qc.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); - - } - else { - - proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; - proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; - - old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); - new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); - - if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); - if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); - - - if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ - - bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); - - if (quorum_met){ - - high_qc.quorum_met = true; - - //ilog("=== updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); - - _high_qc = high_qc; - _b_leaf = _high_qc.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); - - } - - } - - } - - } - - void qc_chain::on_leader_rotate(){ - - ilog("on_leader_rotate"); - - chain::controller& chain = _chain_plug->chain(); - - //verify if leader changed - signed_block_header current_block_header = chain.head_block_state()->header; - - block_timestamp_type next_block_time = current_block_header.timestamp.next(); - - //ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", - // ("old_timestamp", current_block_header.timestamp)("new_timestamp", current_block_header.timestamp.next())); - - producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); - - if (current_block_header.producer != p_auth.producer_name){ - - ilog("/// rotating leader : ${old_leader} -> ${new_leader} ", - ("old_leader", current_block_header.producer)("new_leader", p_auth.producer_name)); - - //leader changed, we send our new_view message - - reset_qc(NULL_PROPOSAL_ID); - - _pending_proposal_block = NULL_BLOCK_ID; - - hs_new_view_message new_view; - - new_view.high_qc = _high_qc; - - broadcast_hs_new_view(new_view); - } - - - } - - //safenode predicate - bool qc_chain::is_node_safe(hs_proposal_message proposal){ - - //ilog("=== is_node_safe ==="); - - bool monotony_check = false; - bool safety_check = false; - bool liveness_check = false; - bool final_on_qc_check = false; - - fc::sha256 upcoming_commit; - - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated - else { - - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - if (chain_length>=2){ - - auto itr = current_qc_chain.begin(); - - hs_proposal_message b2 = *itr; - itr++; - hs_proposal_message b1 = *itr; - - if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; - else { - - proposal_store_type::nth_index<0>::type::iterator p_itr; - - p_itr = _proposal_store.get().find( b1.parent_id ); - - upcoming_commit = p_itr->final_on_qc; - - } - - } - - //abstracted [...] - if (upcoming_commit == proposal.final_on_qc){ - final_on_qc_check = true; - } - - } - - if (proposal.get_height() > _v_height){ - monotony_check = true; - } - - if (_b_lock != NULL_PROPOSAL_ID){ - - //Safety check : check if this proposal extends the chain I'm locked on - if (extends(proposal.proposal_id, _b_lock)){ - safety_check = true; - } - - //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated - else { - - proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); - proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); - - if (prop_justification->get_height() > b_lock->get_height()){ - liveness_check = true; - } - } - - } - else { - - ilog("not locked on anything, liveness and safety are true"); - - //if we're not locked on anything, means the protocol just activated or chain just launched - liveness_check = true; - safety_check = true; - } - -/* ilog("=== final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", - ("final_on_qc_check", final_on_qc_check) - ("monotony_check", monotony_check) - ("liveness_check", liveness_check) - ("safety_check", safety_check));*/ - - return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully - - } - - //on proposal received, called from network thread - void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_proposal_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_proposal_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_proposal(msg); - - //ilog(" === end of on_hs_proposal_msg"); -} -catch (...){ - ilog("error during on_hs_proposal_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on vote received, called from network thread - void qc_chain::on_hs_vote_msg(hs_vote_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_vote_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_vote_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_vote(msg); - - //ilog(" === end of on_hs_vote_msg"); - } -catch (...){ - ilog("error during on_hs_vote_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on new view received, called from network thread - void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_new_view_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_new_view_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_new_view(msg); - - //ilog(" === end of on_hs_new_view_msg"); -} -catch (...){ - ilog("error during on_hs_new_view_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on new block received, called from network thread - void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_new_block_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_new_block_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_new_block(msg); - - //ilog(" === end of on_hs_new_block_msg"); -} -catch (...){ - ilog("error during on_hs_new_block_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - void qc_chain::update(hs_proposal_message proposal){ - - //ilog("=== update internal state ==="); - - chain::controller& chain = _chain_plug->chain(); - - proposal_store_type::nth_index<0>::type::iterator b_lock; - - //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ - ilog("*** proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)); - return; - } - - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - b_lock = _proposal_store.get().find( _b_lock); - - ilog("=== update_high_qc : proposal.justify ==="); - update_high_qc(proposal.justify); - - if (chain_length<1){ - ilog("*** qc chain length is 0"); - return; - } - - auto itr = current_qc_chain.begin(); - hs_proposal_message b_2 = *itr; - - if (chain_length<2){ - ilog("*** qc chain length is 1"); - return; - } - - itr++; - - hs_proposal_message b_1 = *itr; - - //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock - if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ - - //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); - _b_lock = b_1.proposal_id; //commit phase on b1 - - ilog("=== _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)); - - } - - if (chain_length<3){ - ilog("*** qc chain length is 2"); - return; - } - - itr++; - - hs_proposal_message b = *itr; - -/* ilog("direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", - ("b_2.parent_id",b_2.parent_id) - ("b_1.proposal_id", b_1.proposal_id) - ("b_1.parent_id", b_1.parent_id) - ("b.proposal_id", b.proposal_id));*/ - - //direct parent relationship verification - if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ - - //ilog("direct parent relationship verified"); - - - commit(b); - - //ilog("last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); - - //ilog("setting _b_exec to ${proposal_id}", ("proposal_id",b.proposal_id )); - _b_exec = b.proposal_id; //decide phase on b - _block_exec = b.block_id; - - clear_old_data( b.get_height()-1); //todo : figure out what number is actually needed - - //ilog("completed commit"); - - } - else { - - ilog("*** could not verify direct parent relationship"); - - ilog("*** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); - ilog("*** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); - ilog("*** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); - - } - - - } - - void qc_chain::clear_old_data(uint64_t cutoff){ - - //std::lock_guard g1( this->_proposal_store_mutex ); - //std::lock_guard g2( this-> _qc_store_mutex ); - - //ilog("clearing old data"); - - auto end_itr = _proposal_store.get().upper_bound(cutoff); - - while (_proposal_store.get().begin() != end_itr){ - - auto itr = _proposal_store.get().begin(); - - ilog("erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", - ("block_num", itr->block_num()) - ("phase_counter", itr->phase_counter) - ("block_id", itr->block_id) - ("proposal_id", itr->proposal_id)); - - //auto qc_itr = _qc_store.get().find(itr->proposal_id); - - //if (qc_itr!=_qc_store.get().end()) _qc_store.get().erase(qc_itr); - _proposal_store.get().erase(itr); - - - } - - } - - void qc_chain::commit(hs_proposal_message proposal){ - -/* ilog("=== attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", proposal.block_num()) - ("proposal_id", proposal.proposal_id) - ("block_id", proposal.block_id) - ("phase_counter", proposal.phase_counter) - ("parent_id", proposal.parent_id)); - */ - bool sequence_respected = false; - - proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); - -/* ilog("=== _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", last_exec_prop->block_num()) - ("proposal_id", last_exec_prop->proposal_id) - ("block_id", last_exec_prop->block_id) - ("phase_counter", last_exec_prop->phase_counter) - ("parent_id", last_exec_prop->parent_id));*/ - - if (_b_exec==NULL_PROPOSAL_ID){ - //ilog("first block committed"); - sequence_respected = true; - } - else sequence_respected = last_exec_prop->get_height() < proposal.get_height(); - - if (sequence_respected){ - - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); - - if (p_itr != _proposal_store.get().end()){ - - //ilog("=== recursively committing" ); - - commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first - - } - - ilog("=== committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("block_id", proposal.block_id) - ("proposal_id", proposal.proposal_id)); - - } - - } - -}} - - diff --git a/plugins/producer_plugin/qc_chain.old.cpp b/plugins/producer_plugin/qc_chain.old.cpp deleted file mode 100644 index 76ef632e68..0000000000 --- a/plugins/producer_plugin/qc_chain.old.cpp +++ /dev/null @@ -1,573 +0,0 @@ -#include - -namespace eosio { namespace chain { - - digest_type qc_chain::get_digest_to_sign(consensus_msg_type msg_type, uint32_t view_number, digest_type digest_to_sign){ - - string s_cmt = msg_type_to_string(msg_type); - string s_view_number = to_string(view_number); - - string s_c = s_cmt + s_view_number; - - digest_type h1 = digest_type::hash(s_c); - digest_type h2 = digest_type::hash( std::make_pair( h1, digest_to_sign ) ); - - return h2; - - } - - void qc_chain::init(chain_plugin* chain_plug, std::set my_producers){ - - std::vector seed_1 = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, - 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, - 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; - - ilog("init qc chain"); - - _qc_chain_state = initializing; - _my_producers = my_producers; - - _chain_plug = chain_plug; - - _private_key = fc::crypto::blslib::bls_private_key(seed_1); - - } - - //create a new view based on the block we just produced - void qc_chain::create_new_view(block_state hbs){ - - _view_number++; - _view_leader = hbs.header.producer; - _view_finalizers = hbs.active_schedule.producers; - - _qc_chain_state = leading_view; - - digest_type previous_bmroot = hbs.blockroot_merkle.get_root(); - digest_type schedule_hash = hbs.pending_schedule.schedule_hash; - - digest_type header_bmroot = digest_type::hash(std::make_pair(hbs.header.digest(), previous_bmroot)); - digest_type digest_to_sign = digest_type::hash(std::make_pair(header_bmroot, schedule_hash)); - - consensus_node cn = {hbs.header, previous_bmroot, schedule_hash, digest_to_sign}; - - std::optional qc; - - if (_prepareQC.has_value()) qc = _prepareQC.value(); - else qc = std::nullopt; - - consensus_message msg = {cm_prepare, _view_number, cn, qc} ; - - ilog("creating new view #${view_number} : leader : ${view_leader}", - ("view_number", _view_number)("view_leader", _view_leader)); - - vector finalizers; - - _currentQC = {msg.msg_type, msg.view_number, msg.node, finalizers, fc::crypto::blslib::bls_signature("")};; - - emit_new_phase(msg); - - - } - - void qc_chain::request_new_view(){ - - //ilog("request new view"); - - _view_number++; - - _qc_chain_state = processing_view; - - //consensus_node cn = _prepareQC.node; - //consensus_message msg = {cm_new_view, _view_number, cn, std::nullopt}; - - //emit_new_phase(msg); - - } - - //called from network thread - void qc_chain::on_confirmation_msg(confirmation_message msg){ - - std::lock_guard g( this->_confirmation_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_confirmation_msg(msg, false); - - } - - //called from network thread - void qc_chain::on_consensus_msg(consensus_message msg){ - - std::lock_guard g( this->_consensus_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_consensus_msg(msg, false); - - } - - void qc_chain::process_confirmation_msg(confirmation_message msg, bool self_confirming){ - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == _view_leader; }); - - if (prod_itr==_my_producers.end()) return; //if we're not producing, we can ignore any confirmation messages - -/* ilog("got notified of confirmation message: ${msg_type} for view ${view_number} ${self_confirming}", - ("msg_type", msg.msg_type) - ("view_number", msg.view_number) - ("self_confirming", self_confirming));*/ - - auto itr = std::find_if(_processed_confirmation_msgs.begin(), _processed_confirmation_msgs.end(), [ &msg](confirmation_message m){ - return m.msg_type == msg.msg_type && - m.view_number == msg.view_number && - m.node.digest_to_sign == msg.node.digest_to_sign && - m.finalizer == msg.finalizer; - }); - - if (itr!=_processed_confirmation_msgs.end()) { - //ilog("WRONG already processed this message"); - return; //already processed - } - else{ - //ilog("new confirmation message. Processing..."); - _processed_confirmation_msgs.push_back(msg); - - if (_processed_confirmation_msgs.size()==100) _processed_confirmation_msgs.erase(_processed_confirmation_msgs.begin()); - - } - - if (_currentQC.msg_type == msg.msg_type && //check if confirmation message is for that QC - _currentQC.view_number == msg.view_number){ - - if (std::find(_currentQC.finalizers.begin(), _currentQC.finalizers.end(), msg.finalizer) == _currentQC.finalizers.end()){ - - //ilog("new finalizer vote received for this QC"); - - //verify signature - fc::crypto::blslib::bls_public_key pk = _private_key.get_public_key(); - - digest_type digest = get_digest_to_sign(msg.msg_type, msg.view_number, msg.node.digest_to_sign ); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - bool ok = verify(pk, h, msg.sig); - -/* ilog("verification - key: ${pk} hash: ${h} sig: ${sig}", - ("agg_pk", pk.to_string()) - ("h", h) - ("sig", msg.sig.to_string()));*/ - - if (ok==false){ - //ilog("WRONG signature invalid"); - return; - } - - fc::crypto::blslib::bls_signature n_sig; - - if (_currentQC.finalizers.size() == 0) n_sig = msg.sig; - else n_sig = fc::crypto::blslib::aggregate({_currentQC.sig,msg.sig}); - -/* ilog("n_sig updated : ${n_sig}", - ("n_sig", n_sig.to_string()));*/ - - _currentQC.sig = n_sig; - _currentQC.finalizers.push_back(msg.finalizer); - - if (_currentQC.finalizers.size()==14){ - - ilog("reached quorum on ${msg_type}, can proceed with next phase", - ("msg_type", msg.msg_type)); - - //received enough confirmations to move to next phase - consensus_msg_type next_phase; - - switch (_currentQC.msg_type) { - case cm_prepare: - next_phase = cm_pre_commit; - _prepareQC = _currentQC; - break; - case cm_pre_commit: - next_phase = cm_commit; - break; - case cm_commit: - next_phase = cm_decide; - break; - } - - consensus_message n_msg = {next_phase, _currentQC.view_number, _currentQC.node, _currentQC}; - - vector finalizers; - - quorum_certificate qc = {next_phase, _currentQC.view_number, _currentQC.node, finalizers, fc::crypto::blslib::bls_signature("")}; - - _currentQC = qc; - - emit_new_phase(n_msg); - - //ilog("sent next phase message"); - - if (next_phase==cm_decide){ - - uint32_t block_height = n_msg.node.header.block_num(); - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - uint32_t distance_from_head = hbs->header.block_num() - block_height; - - ilog("decide decision has been reached on view #${view_number}. Block #${block_height} can be commited safely. Distance from head : ${distance_from_head}", - ("view_number", msg.view_number) - ("block_height", block_height) - ("distance_from_head", distance_from_head)); - - _qc_chain_state=finished_view; - - //if we're still producing, we can start a new view - if (std::find(_my_producers.begin(), _my_producers.end(), hbs->header.producer) != _my_producers.end()){ - create_new_view(*hbs); - } - - } - - } - else { - //uint32_t remaining = 14 - _currentQC.finalizers.size(); - - //ilog("need ${remaining} more votes to move to next phase", ("remaining", remaining)); - } - - } - else { - //ilog("WRONG already received vote for finalizer on this QC "); - - - } - - } - else { - //confirmation applies to another message - //ilog("WRONG QC"); - - } - - } - - void qc_chain::process_consensus_msg(consensus_message msg, bool self_leading){ - -/* ilog("got notified of consensus message: ${msg_type} for view ${view_number} ${self_leading}", - ("msg_type", msg.msg_type) - ("view_number", msg.view_number) - ("self_leading", self_leading));*/ - - auto itr = std::find_if(_processed_consensus_msgs.begin(), _processed_consensus_msgs.end(), [ &msg](consensus_message m){ - return m.msg_type == msg.msg_type && - m.view_number == msg.view_number && - m.node.digest_to_sign == msg.node.digest_to_sign; - }); - - if (itr!=_processed_consensus_msgs.end()){ - //ilog("WRONG already processed this message"); - return; //already processed - } - else { - //ilog("new consensus message. Processing..."); - _processed_consensus_msgs.push_back(msg); - - if (_processed_consensus_msgs.size()==100) _processed_consensus_msgs.erase(_processed_consensus_msgs.begin()); - - } - - //TODO validate message - - digest_type digest = get_digest_to_sign(msg.msg_type, msg.view_number, msg.node.digest_to_sign ); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - //if we're leading the view, reject the consensus message - //if (_qc_chain_state==leading_view) return; - - if (msg.justify.has_value()) { - - auto justify = msg.justify.value(); - - if (justify.finalizers.size() == 14){ - - fc::crypto::blslib::bls_public_key agg_pk = _private_key.get_public_key(); - - //verify QC - for (size_t i = 1 ; i < justify.finalizers.size();i++){ - agg_pk = fc::crypto::blslib::aggregate({agg_pk,_private_key.get_public_key()}); - } - - digest_type digest_j = get_digest_to_sign(justify.msg_type, justify.view_number, justify.node.digest_to_sign ); - std::vector hj = std::vector(digest_j.data(), digest_j.data() + 32); - -/* ilog("agg verification - key: ${agg_pk} hash: ${hj} sig: ${sig}", - ("agg_pk", agg_pk.to_string()) - ("hj", hj) - ("sig", justify.sig.to_string()));*/ - - bool ok = verify(agg_pk, hj, justify.sig); - - if (ok==false){ - //ilog("WRONG aggregate signature invalid"); - return; - } - - _view_number = msg.view_number; - - if (justify.msg_type == cm_pre_commit){ - _prepareQC = justify; - } - else if (justify.msg_type == cm_pre_commit){ - _lockedQC = justify; - } - } - else { - - //ilog("WRONG invalid consensus message justify argument"); - - return ; - } - } - - if (_qc_chain_state==initializing || _qc_chain_state==finished_view ) { - _view_number = msg.view_number; - _view_leader = msg.node.header.producer; - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - _view_finalizers = hbs->active_schedule.producers; - - _qc_chain_state=processing_view; - - } - - //if we received a commit decision and we are not also leading this round - if (msg.msg_type == cm_decide && self_leading == false){ - - uint32_t block_height = msg.node.header.block_num(); - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - uint32_t distance_from_head = hbs->header.block_num() - block_height; - - ilog("decide decision has been reached on view #${view_number}. Block #${block_height} can be commited safely. Distance from head : ${distance_from_head}", - ("view_number", msg.view_number) - ("block_height", block_height) - ("distance_from_head", distance_from_head)); - - //if current producer is not previous view leader, we must send a new_view message with our latest prepareQC - if (hbs->header.producer != _view_leader){ - //_view_number++; - _view_leader = hbs->header.producer; - _qc_chain_state=finished_view; - } - - return; - - } - else { - - auto p_itr = _my_producers.begin(); - - while(p_itr!= _my_producers.end()){ - - chain::account_name finalizer = *p_itr; - - auto itr = std::find_if(_view_finalizers.begin(), _view_finalizers.end(), [&](const auto& asp){ return asp.producer_name == finalizer; }); - - if (itr!= _view_finalizers.end()){ - - //ilog("Signing confirmation..."); - - fc::crypto::blslib::bls_signature sig = _private_key.sign(h);; - -/* ilog("signing confirmation message : ${h} - ${sig}", - ("h", h) - ("sig", sig.to_string()));*/ - - confirmation_message n_msg = {msg.msg_type, msg.view_number, msg.node, finalizer, sig}; - - //ilog("Sending confirmation message for ${finalizer}", ("finalizer", finalizer)); - - emit_confirm(n_msg); - - } - else { - //finalizer not in view schedule - //ilog("WRONG consensus ${finalizer}", ("finalizer", finalizer)); - - } - - p_itr++; - } - - } - } - - void qc_chain::emit_confirm(confirmation_message msg){ - - chain::controller& chain = _chain_plug->chain(); - -/* ilog("emit confirm ${msg_type}... view #${view_number} on block ${block_id}, digest to sign is : ${digest} ", - ("msg_type",msg.msg_type) - ("view_number",msg.view_number) - ("block_id",msg.node.header.calculate_id()) - ("digest",msg.node.digest_to_sign) );*/ - - confirmation_message_ptr ptr = std::make_shared(msg); - - chain.commit_confirmation_msg(ptr); - - process_confirmation_msg(msg, true); //notify ourselves, in case we are also the view leader - - } - - void qc_chain::emit_new_phase(consensus_message msg){ - - chain::controller& chain = _chain_plug->chain(); - - ilog("emit new phase ${msg_type}... view #${view_number} on block #${block_num}", - ("msg_type",msg.msg_type) - ("view_number",msg.view_number) - ("block_num",msg.node.header.block_num()) ); - - - //if (msg.justify.has_value()){ - - // auto justify = msg.justify.value(); - -/* ilog(" justify : view #${view_number} on block ${block_id}, digest to sign is : ${digest} ", - ("msg_type",justify.msg_type) - ("view_number",justify.view_number) - ("block_id",justify.node.header.calculate_id()) - ("digest",justify.node.digest_to_sign) );*/ - - //} - - consensus_message_ptr ptr = std::make_shared(msg); - - chain.commit_consensus_msg(ptr); - - process_consensus_msg(msg, true); //notify ourselves, in case we are also running finalizers - - } - - void qc_chain::on_new_view_interrupt(){ - - } - - void qc_chain::commit(block_header header){ - - } - - void qc_chain::print_state(){ - - ilog("QC CHAIN STATE : "); - - ilog(" view number : ${view_number}, view leader : ${view_leader}", - ("view_number", _view_number) - ("view_leader", _view_leader)); - - - if (_prepareQC.has_value()){ - - quorum_certificate prepareQC = _prepareQC.value(); - - ilog(" prepareQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", - ("msg_type", prepareQC.msg_type) - ("view_number", prepareQC.view_number) - ("block_num", prepareQC.node.header.block_num())); - - ilog(" finalizers : "); - - for (int i = 0 ; i < prepareQC.finalizers.size(); i++){ - ilog(" ${finalizer}", - ("finalizer", prepareQC.finalizers[i])); - } - - } - else { - ilog(" no prepareQC"); - } - - - if (_lockedQC.has_value()){ - - quorum_certificate lockedQC = _lockedQC.value(); - - ilog(" lockedQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", - ("msg_type", lockedQC.msg_type) - ("view_number", lockedQC.view_number) - ("block_num", lockedQC.node.header.block_num())); - - ilog(" finalizers : "); - - for (int i = 0 ; i < lockedQC.finalizers.size(); i++){ - ilog(" ${finalizer}", - ("finalizer", lockedQC.finalizers[i])); - } - - } - else { - ilog(" no _lockedQC"); - } - - ilog(" _currentQC type: ${msg_type} view: #${view_number} block_num: ${block_num}", - ("msg_type", _currentQC.msg_type) - ("view_number", _currentQC.view_number) - ("block_num", _currentQC.node.header.block_num())); - - ilog(" finalizers : "); - - for (int i = 0 ; i < _currentQC.finalizers.size(); i++){ - ilog(" ${finalizer}", - ("finalizer", _currentQC.finalizers[i])); - } - - ilog(" _processed_confirmation_msgs count : ${count}", - ("count", _processed_confirmation_msgs.size())); - - ilog(" _processed_consensus_msgs count : ${count}", - ("count", _processed_consensus_msgs.size())); - -/* - - struct quorum_certificate { - - consensus_msg_type msg_type; - uint32_t view_number; - consensus_node node; - - vector finalizers; - bls_signature_type sig; - - }; - - std::set _my_producers; - - qc_chain_state _qc_chain_state; - - uint32_t _view_number; - chain::account_name _view_leader; - vector _view_finalizers; - - std::optional _prepareQC; - std::optional _lockedQC; - - fc::crypto::blslib::bls_private_key _private_key; - - quorum_certificate _currentQC; - - uint32_t _view_liveness_threshold; - - vector _processed_confirmation_msgs; - vector _processed_consensus_msgs; - -*/ - - } - -}} \ No newline at end of file diff --git a/plugins/producer_plugin/qc_chain.old2.cpp b/plugins/producer_plugin/qc_chain.old2.cpp deleted file mode 100644 index 093174fc82..0000000000 --- a/plugins/producer_plugin/qc_chain.old2.cpp +++ /dev/null @@ -1,1216 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -#include -#include - -#include - -//todo list / notes : - -/* - - - -fork tests in unittests - - - -network plugin versioning - -handshake_message.network_version - -independant of protocol feature activation - - - -separate library for hotstuff (look at SHIP libray used by state history plugin ) - - -boost tests producer plugin test - - - -regression tests python framework as a base - - - -performance testing - - - - -*/ - - - -// -// complete proposer / leader differentiation -// integration with new bls implementation -// -// hotstuff as a library with its own tests (model on state history plugin + state_history library ) -// -// unit / integration tests -> producer_plugin + fork_tests tests as a model -// -// test deterministic sequence -// -// test non-replica participation -// test finality vioaltion -// test loss of liveness -// -// test split chain -// -// integration with fork_db / LIB overhaul -// -// integration with performance testing -// -// regression testing ci/cd -> python regression tests -// -// add APIs for proof data -// -// add election proposal in block header -// -// map proposers / finalizers / leader to new host functions -// -// support pause / resume producer -// -// keep track of proposals sent to peers -// -// allow syncing of proposals -// -// versioning of net protocol version -// -// protocol feature activation HOTSTUFF_CONSENSUS -// -// system contract update 1 -> allow BPs to register + prove their aggregate pub key. Allow existing BPs to unreg + reg without new aggregate key. Prevent new BPs from registering without proving aggregate pub key -// -// system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) -> skip BPs without a bls key in the selection, new host functions are available -// -// - - -namespace eosio { namespace chain { - using boost::multi_index_container; - using namespace boost::multi_index; - - //todo : remove. bls12-381 key used for testing purposes - std::vector _seed = { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, - 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, - 12, 62, 89, 110, 182, 9, 44, 20, 254, 22}; - - fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); - - enum msg_type { - new_view = 1, - new_block = 2, - qc = 3, - vote = 4 - }; - - uint32_t _v_height; - - bool _chained_mode = false ; - - void handle_eptr(std::exception_ptr eptr){ - try { - if (eptr) { - std::rethrow_exception(eptr); - } - } catch(const std::exception& e) { - ilog("Caught exception ${ex}" , ("ex", e.what())); - std::exit(0); - } - } - - const block_id_type NULL_BLOCK_ID = block_id_type("00"); - const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - -/* const block_header_state_ptr NULL_BLOCK_HEADER_STATE_PTR = block_header_state_ptr(); - const block_state_ptr NULL_BLOCK_STATE_PTR = block_state_ptr();*/ - - fc::sha256 _b_leaf = NULL_PROPOSAL_ID; - fc::sha256 _b_lock = NULL_PROPOSAL_ID; - fc::sha256 _b_exec = NULL_PROPOSAL_ID; - - block_id_type _block_exec = NULL_BLOCK_ID; - - eosio::chain::quorum_certificate _high_qc; - eosio::chain::quorum_certificate _current_qc; - - eosio::chain::extended_schedule _schedule; - - chain_plugin* _chain_plug = nullptr; - std::set _my_producers; - - block_id_type _pending_proposal_block = NULL_BLOCK_ID; - - struct by_proposal_id{}; - struct by_proposal_height{}; - - typedef multi_index_container< - hs_proposal_message, - indexed_by< - hashed_unique< - tag, - BOOST_MULTI_INDEX_MEMBER(hs_proposal_message,fc::sha256,proposal_id) - >, - ordered_unique< - tag, - BOOST_MULTI_INDEX_CONST_MEM_FUN(hs_proposal_message,uint64_t,get_height) - > - > - > proposal_store_type; - - proposal_store_type _proposal_store; - - - digest_type get_digest_to_sign(block_id_type block_id, uint8_t phase_counter, fc::sha256 final_on_qc){ - - digest_type h1 = digest_type::hash( std::make_pair( block_id, phase_counter ) ); - digest_type h2 = digest_type::hash( std::make_pair( h1, final_on_qc ) ); - - return h2; - - } - - std::vector qc_chain::get_qc_chain(fc::sha256 proposal_id){ - - std::vector ret_arr; - - proposal_store_type::nth_index<0>::type::iterator b_2_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_1_itr = _proposal_store.get().end(); - proposal_store_type::nth_index<0>::type::iterator b_itr = _proposal_store.get().end(); - - b_2_itr = _proposal_store.get().find( proposal_id ); - if (b_2_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_1_itr = _proposal_store.get().find( b_2_itr->justify.proposal_id ); - if (b_1_itr->justify.proposal_id != NULL_PROPOSAL_ID) b_itr = _proposal_store.get().find( b_1_itr->justify.proposal_id ); - - if (b_2_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_2_itr); - if (b_1_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_1_itr); - if (b_itr!=_proposal_store.get().end()) ret_arr.push_back(*b_itr); - - return ret_arr; - - } - - name qc_chain::get_proposer(){ - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - return hbs->header.producer; - - } - - name qc_chain::get_leader(){ - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - return hbs->header.producer; - - } - - - std::vector qc_chain::get_finalizers(){ - - chain::controller& chain = _chain_plug->chain(); - - const auto& hbs = chain.head_block_state(); - - return hbs->active_schedule.producers; - - } - - hs_proposal_message qc_chain::new_proposal_candidate(block_id_type block_id, uint8_t phase_counter) { - - hs_proposal_message b_new; - - b_new.block_id = block_id; - b_new.parent_id = _b_leaf; - b_new.phase_counter = phase_counter; - - b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - - if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ - - std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - if (chain_length>=2){ - - auto itr = current_qc_chain.begin(); - - hs_proposal_message b2 = *itr; - itr++; - hs_proposal_message b1 = *itr; - - if (b_new.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) b_new.final_on_qc = b1.proposal_id; - else { - - proposal_store_type::nth_index<0>::type::iterator p_itr; - - p_itr = _proposal_store.get().find( b1.parent_id ); - - b_new.final_on_qc = p_itr->final_on_qc; - - } - - } - - } - - b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); - - ilog("=== creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", - ("block_num", b_new.block_num()) - ("phase_counter", b_new.phase_counter) - ("proposal_id", b_new.proposal_id) - ("parent_id", b_new.parent_id) - ("justify", b_new.justify.proposal_id)); - - return b_new; - - } - - void reset_qc(fc::sha256 proposal_id){ - - _current_qc.proposal_id = proposal_id; - _current_qc.quorum_met = false; - _current_qc.active_finalizers = {}; - _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); - - } - - hs_new_block_message qc_chain::new_block_candidate(block_id_type block_id) { - - hs_new_block_message b; - - b.block_id = block_id; - b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - - return b; - } - - bool evaluate_quorum(extended_schedule es, vector finalizers, fc::crypto::blslib::bls_signature agg_sig, hs_proposal_message proposal){ -/* -std::exception_ptr eptr; -try{*/ - - if (finalizers.size() < _threshold){ - return false; - } - - fc::crypto::blslib::bls_public_key agg_key; - - for (int i = 0; i < finalizers.size(); i++) { - - //adding finalizer's key to the aggregate pub key - if (i==0) agg_key = _private_key.get_public_key(); - else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); - - } - - fc::crypto::blslib::bls_signature justification_agg_sig; - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; - - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - bool ok = fc::crypto::blslib::verify(agg_key, h, agg_sig); - - return ok; - -/*} -catch (...){ - ilog("error during evaluate_quorum"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr);*/ - - } - - bool qc_chain::is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal){ - -/*std::exception_ptr eptr; -try{ -*/ - if (qc.quorum_met == true ) { - return true; //skip evaluation if we've already verified quorum was met - } - else { - - //ilog("qc : ${qc}", ("qc", qc)); - - bool quorum_met = evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); - - qc.quorum_met = quorum_met; - - return qc.quorum_met ; - - } -/*} -catch (...){ - ilog("error during find proposals"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr);*/ - } - - void qc_chain::init(chain_plugin& chain_plug, std::set my_producers){ - - _chain_plug = &chain_plug; - _my_producers = my_producers; - - //ilog("qc chain initialized -> my producers : "); - - - } - - block_header_state_ptr qc_chain::get_block_header( const block_id_type& id ){ - - //ilog("get_block_header "); - - chain::controller& chain = _chain_plug->chain(); - - return chain.fork_db().get_block_header(id); - - } - - bool qc_chain::am_i_proposer(){ - - name proposer = get_proposer(); - - //ilog("Proposer : ${proposer}", ("proposer", proposer)); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == proposer; }); - - if (prod_itr==_my_producers.end()) return false; - else return true; - - } - - bool qc_chain::am_i_leader(){ - - name leader = get_leader(); - - //ilog("Leader : ${leader}", ("leader", leader)); - - auto prod_itr = std::find_if(_my_producers.begin(), _my_producers.end(), [&](const auto& asp){ return asp == leader; }); - - if (prod_itr==_my_producers.end()) return false; - else return true; - - } - - bool qc_chain::am_i_finalizer(){ - - //ilog("am_i_finalizer"); - - std::vector finalizers = get_finalizers(); - - auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); - - if (prod_itr!=finalizers.end()) return true; - - mf_itr++; - - } - - return false; - - } - - void qc_chain::process_proposal(hs_proposal_message proposal){ - - - auto itr = _proposal_store.get().find( proposal.proposal_id ); - - if (itr != _proposal_store.get().end()) { - ilog("*** proposal received twice : ${proposal_id}",("proposal_id", proposal.proposal_id)); - return ; //already aware of proposal, nothing to do - - } - - ilog("=== received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id) - ("parent_id", proposal.parent_id) - ("justify", proposal.justify.proposal_id)); - - _proposal_store.insert(proposal); //new proposal - - bool am_finalizer = am_i_finalizer(); - bool node_safe = is_node_safe(proposal); - - bool signature_required = am_finalizer && node_safe; - - //if I am a finalizer for this proposal, test safenode predicate for possible vote - if (signature_required){ - - //ilog("signature required"); - - _v_height = proposal.get_height(); - - fc::crypto::blslib::bls_signature agg_sig; - - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) agg_sig = proposal.justify.active_agg_sig; - - digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); - - std::vector h = std::vector(digest.data(), digest.data() + 32); - - //iterate over all my finalizers and sign / broadcast for each that is in the schedule - std::vector finalizers = get_finalizers(); - - //ilog("signed proposal. Broadcasting for each of my producers"); - - auto mf_itr = _my_producers.begin(); - - while(mf_itr!=_my_producers.end()){ - - auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f.producer_name == *mf_itr; }); - - if (prod_itr!=finalizers.end()) { - - fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //todo : use appropriate private key for each producer - - hs_vote_message v_msg = {proposal.proposal_id, prod_itr->producer_name, sig}; - - broadcast_hs_vote(v_msg); - - }; - - mf_itr++; - - } - - } - - //update internal state - update(proposal); - - //check for leader change - on_leader_rotate(); - - } - - void qc_chain::process_vote(hs_vote_message vote){ - - //check for duplicate or invalid vote, return in either case - //abstracted [...] - - bool am_leader = am_i_leader(); //am I leader? - - if(!am_leader) return; - - //ilog("=== Process vote from ${finalizer}", ("finalizer", vote.finalizer)); - - //only leader need to take action on votes - - if (vote.proposal_id != _current_qc.proposal_id) return; - - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find(vote.proposal_id ); - - if (p_itr==_proposal_store.get().end()){ - ilog("*** couldn't find proposal"); - - ilog("*** vote : ${vote}", ("vote", vote)); - - return; - } - - bool quorum_met = _current_qc.quorum_met; //check if quorum already met - - if (!quorum_met){ - - _current_qc.active_finalizers.push_back(vote.finalizer); - - if (_current_qc.active_finalizers.size()>1) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); - else _current_qc.active_agg_sig = vote.sig; - - quorum_met = is_quorum_met(_current_qc, _schedule, *p_itr); - - if (quorum_met){ - - _current_qc.quorum_met = true; - - //ilog("=== Quorum met on #${block_num} ${proposal_id} ", ("block_num", p_itr->block_num())("proposal_id", vote.proposal_id)); - - ilog("=== update_high_qc : _current_qc ==="); - update_high_qc(_current_qc); - - //check for leader change - on_leader_rotate(); - - - //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet - if (_chained_mode==false && p_itr->phase_counter<3){ - - hs_proposal_message proposal_candidate; - - if (_pending_proposal_block == NULL_BLOCK_ID) proposal_candidate = new_proposal_candidate(p_itr->block_id, p_itr->phase_counter + 1 ); - else proposal_candidate = new_proposal_candidate(_pending_proposal_block, 0); - - reset_qc(proposal_candidate.proposal_id); - - _pending_proposal_block = NULL_BLOCK_ID; - - broadcast_hs_proposal(proposal_candidate); - - _b_leaf = proposal_candidate.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); - - } - - } - - } - - } - - void qc_chain::process_new_view(hs_new_view_message new_view){ - - ilog("=== update_high_qc : process_new_view === ${qc}", ("qc", new_view.high_qc)); - update_high_qc(new_view.high_qc); - - } - - void qc_chain::process_new_block(hs_new_block_message msg){ - - //ilog("=== Process new block ==="); - - } - - void qc_chain::broadcast_hs_proposal(hs_proposal_message msg){ - - //ilog("=== broadcast_hs_proposal ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_proposal_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_proposal_msg(ptr); - - process_proposal(msg); - - } - - - void qc_chain::broadcast_hs_vote(hs_vote_message msg){ - - //ilog("=== broadcast_hs_vote ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_vote_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_vote_msg(ptr); - - process_vote(msg); - - } - - void qc_chain::broadcast_hs_new_view(hs_new_view_message msg){ - - //ilog("=== broadcast_hs_new_view ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_new_view_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_new_view_msg(ptr); - - //process_new_view(msg); //notify ourselves - - } - - void qc_chain::broadcast_hs_new_block(hs_new_block_message msg){ - - //ilog("=== broadcast_hs_new_block ==="); - - chain::controller& chain = _chain_plug->chain(); - - hs_new_block_message_ptr ptr = std::make_shared(msg); - - chain.commit_hs_new_block_msg(ptr); - - //process_new_block(msg); //notify ourselves - - } - - //extends predicate - bool qc_chain::extends(fc::sha256 descendant, fc::sha256 ancestor){ - - - //todo : confirm the extends predicate never has to verify extension of irreversible blocks, otherwise this function needs to be modified - - - proposal_store_type::nth_index<0>::type::iterator itr = _proposal_store.get().find(descendant ); - - uint32_t counter = 0; - - while (itr!=_proposal_store.get().end()){ - - itr = _proposal_store.get().find(itr->parent_id ); - - if (itr->proposal_id == ancestor){ - if (counter>25) { - ilog("***"); - ilog("*** took ${counter} iterations to find ancestor ", ("counter", counter)); - ilog("***"); - - } - return true; - } - - counter++; - - } - - ilog(" ***** extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", - ("d_proposal_id", descendant) - ("a_proposal_id", ancestor)); - - return false; - - } - - void qc_chain::on_beat(block_state& hbs){ -std::exception_ptr eptr; -try{ - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - ilog("=== on beat ==="); - - if (hbs.header.producer == "eosio"_n) return ; //if chain has not been activated and doesn't have finalizers, we don't generate proposals - - bool am_proposer = am_i_proposer(); - bool am_leader = am_i_leader(); - - //ilog("=== am_proposer = ${am_proposer}", ("am_proposer", am_proposer)); - //ilog("=== am_leader = ${am_leader}", ("am_leader", am_leader)); - - if (!am_proposer && !am_leader){ - - return; //nothing to do - - } - - //if I am the leader - if (am_leader){ - - //if I'm not also the proposer, perform block validation as required - if (!am_proposer){ - - //todo : extra validation - - } - - - if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false){ - - _pending_proposal_block = hbs.header.calculate_id(); - - } - else { - - hs_proposal_message proposal_candidate = new_proposal_candidate(hbs.header.calculate_id(), 0 ); - - reset_qc(proposal_candidate.proposal_id); - - _pending_proposal_block = NULL_BLOCK_ID; - - broadcast_hs_proposal(proposal_candidate); - - _b_leaf = proposal_candidate.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)); - - } - - } - else { - - //if I'm only a proposer and not the leader, I send a new block message - - hs_new_block_message block_candidate = new_block_candidate(hbs.header.calculate_id()); - - //ilog("=== broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); - - broadcast_hs_new_block(block_candidate); - - } - - //ilog(" === end of on_beat"); -} -catch (...){ - ilog("error during on_beat"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - void qc_chain::update_high_qc(eosio::chain::quorum_certificate high_qc){ - - ilog("=== check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); - - // if new high QC is higher than current, update to new - - - if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ - - _high_qc = high_qc; - _b_leaf = _high_qc.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); - - } - else { - - proposal_store_type::nth_index<0>::type::iterator old_high_qc_prop; - proposal_store_type::nth_index<0>::type::iterator new_high_qc_prop; - - old_high_qc_prop = _proposal_store.get().find( _high_qc.proposal_id ); - new_high_qc_prop = _proposal_store.get().find( high_qc.proposal_id ); - - if (old_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND OLD HIGH QC PROPOSAL"); - if (new_high_qc_prop == _proposal_store.get().end()) return; //ilog(" *** CAN'T FIND NEW HIGH QC PROPOSAL"); - - - if (new_high_qc_prop->get_height()>old_high_qc_prop->get_height()){ - - bool quorum_met = is_quorum_met(high_qc, _schedule, *new_high_qc_prop); - - if (quorum_met){ - - high_qc.quorum_met = true; - - //ilog("=== updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); - - _high_qc = high_qc; - _b_leaf = _high_qc.proposal_id; - - ilog("=== _b_leaf updated : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)); - - } - - } - - } - - } - - void qc_chain::on_leader_rotate(){ - - ilog("on_leader_rotate"); - - chain::controller& chain = _chain_plug->chain(); - - //verify if leader changed - signed_block_header current_block_header = chain.head_block_state()->header; - - block_timestamp_type next_block_time = current_block_header.timestamp.next(); - - //ilog("timestamps : old ${old_timestamp} -> new ${new_timestamp} ", - // ("old_timestamp", current_block_header.timestamp)("new_timestamp", current_block_header.timestamp.next())); - - producer_authority p_auth = chain.head_block_state()->get_scheduled_producer(next_block_time); - - if (current_block_header.producer != p_auth.producer_name){ - - ilog("/// rotating leader : ${old_leader} -> ${new_leader} ", - ("old_leader", current_block_header.producer)("new_leader", p_auth.producer_name)); - - //leader changed, we send our new_view message - - reset_qc(NULL_PROPOSAL_ID); - - _pending_proposal_block = NULL_BLOCK_ID; - - hs_new_view_message new_view; - - new_view.high_qc = _high_qc; - - broadcast_hs_new_view(new_view); - } - - - } - - //safenode predicate - bool qc_chain::is_node_safe(hs_proposal_message proposal){ - - //ilog("=== is_node_safe ==="); - - bool monotony_check = false; - bool safety_check = false; - bool liveness_check = false; - bool final_on_qc_check = false; - - fc::sha256 upcoming_commit; - - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated - else { - - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - if (chain_length>=2){ - - auto itr = current_qc_chain.begin(); - - hs_proposal_message b2 = *itr; - itr++; - hs_proposal_message b1 = *itr; - - if (proposal.parent_id == b2.proposal_id && b2.parent_id == b1.proposal_id) upcoming_commit = b1.proposal_id; - else { - - proposal_store_type::nth_index<0>::type::iterator p_itr; - - p_itr = _proposal_store.get().find( b1.parent_id ); - - upcoming_commit = p_itr->final_on_qc; - - } - - } - - //abstracted [...] - if (upcoming_commit == proposal.final_on_qc){ - final_on_qc_check = true; - } - - } - - if (proposal.get_height() > _v_height){ - monotony_check = true; - } - - if (_b_lock != NULL_PROPOSAL_ID){ - - //Safety check : check if this proposal extends the chain I'm locked on - if (extends(proposal.proposal_id, _b_lock)){ - safety_check = true; - } - - //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated - else { - - proposal_store_type::nth_index<0>::type::iterator b_lock = _proposal_store.get().find( _b_lock ); - proposal_store_type::nth_index<0>::type::iterator prop_justification = _proposal_store.get().find( proposal.justify.proposal_id ); - - if (prop_justification->get_height() > b_lock->get_height()){ - liveness_check = true; - } - } - - } - else { - - ilog("not locked on anything, liveness and safety are true"); - - //if we're not locked on anything, means the protocol just activated or chain just launched - liveness_check = true; - safety_check = true; - } - -/* ilog("=== final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", - ("final_on_qc_check", final_on_qc_check) - ("monotony_check", monotony_check) - ("liveness_check", liveness_check) - ("safety_check", safety_check));*/ - - return final_on_qc_check && monotony_check && (liveness_check || safety_check); //return true if monotony check and at least one of liveness or safety check evaluated successfully - - } - - //on proposal received, called from network thread - void qc_chain::on_hs_proposal_msg(hs_proposal_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_proposal_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_proposal_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_proposal(msg); - - //ilog(" === end of on_hs_proposal_msg"); -} -catch (...){ - ilog("error during on_hs_proposal_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on vote received, called from network thread - void qc_chain::on_hs_vote_msg(hs_vote_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_vote_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_vote_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_vote(msg); - - //ilog(" === end of on_hs_vote_msg"); - } -catch (...){ - ilog("error during on_hs_vote_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on new view received, called from network thread - void qc_chain::on_hs_new_view_msg(hs_new_view_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_new_view_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_new_view_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_new_view(msg); - - //ilog(" === end of on_hs_new_view_msg"); -} -catch (...){ - ilog("error during on_hs_new_view_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - //on new block received, called from network thread - void qc_chain::on_hs_new_block_msg(hs_new_block_message msg){ -std::exception_ptr eptr; -try{ - - //ilog("=== on_hs_new_block_msg ==="); - - std::lock_guard g( this-> _hotstuff_state_mutex ); - - //std::lock_guard g( this->_new_block_mutex ); //lock mutex to prevent multiple concurrent threads from accessing code block - - process_new_block(msg); - - //ilog(" === end of on_hs_new_block_msg"); -} -catch (...){ - ilog("error during on_hs_new_block_msg"); - eptr = std::current_exception(); // capture -} -handle_eptr(eptr); - } - - void qc_chain::update(hs_proposal_message proposal){ - - //ilog("=== update internal state ==="); - - chain::controller& chain = _chain_plug->chain(); - - proposal_store_type::nth_index<0>::type::iterator b_lock; - - //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ - ilog("*** proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)); - return; - } - - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); - - size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); - - b_lock = _proposal_store.get().find( _b_lock); - - ilog("=== update_high_qc : proposal.justify ==="); - update_high_qc(proposal.justify); - - if (chain_length<1){ - ilog("*** qc chain length is 0"); - return; - } - - auto itr = current_qc_chain.begin(); - hs_proposal_message b_2 = *itr; - - if (chain_length<2){ - ilog("*** qc chain length is 1"); - return; - } - - itr++; - - hs_proposal_message b_1 = *itr; - - //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock - if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ - - //ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); - _b_lock = b_1.proposal_id; //commit phase on b1 - - ilog("=== _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)); - - } - - if (chain_length<3){ - ilog("*** qc chain length is 2"); - return; - } - - itr++; - - hs_proposal_message b = *itr; - -/* ilog("direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", - ("b_2.parent_id",b_2.parent_id) - ("b_1.proposal_id", b_1.proposal_id) - ("b_1.parent_id", b_1.parent_id) - ("b.proposal_id", b.proposal_id));*/ - - //direct parent relationship verification - if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ - - //ilog("direct parent relationship verified"); - - - commit(b); - - //ilog("last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); - - //ilog("setting _b_exec to ${proposal_id}", ("proposal_id",b.proposal_id )); - _b_exec = b.proposal_id; //decide phase on b - _block_exec = b.block_id; - - clear_old_data( b.get_height()-1); //todo : figure out what number is actually needed - - //ilog("completed commit"); - - } - else { - - ilog("*** could not verify direct parent relationship"); - - ilog("*** b_2 #${block_num} ${b_2}", ("b_2", b_2)("block_num", b_2.block_num())); - ilog("*** b_1 #${block_num} ${b_1}", ("b_1", b_1)("block_num", b_1.block_num())); - ilog("*** b #${block_num} ${b}", ("b", b)("block_num", b.block_num())); - - } - - - } - - void qc_chain::clear_old_data(uint64_t cutoff){ - - //std::lock_guard g1( this->_proposal_store_mutex ); - //std::lock_guard g2( this-> _qc_store_mutex ); - - //ilog("clearing old data"); - - auto end_itr = _proposal_store.get().upper_bound(cutoff); - - while (_proposal_store.get().begin() != end_itr){ - - auto itr = _proposal_store.get().begin(); - - ilog("erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", - ("block_num", itr->block_num()) - ("phase_counter", itr->phase_counter) - ("block_id", itr->block_id) - ("proposal_id", itr->proposal_id)); - - //auto qc_itr = _qc_store.get().find(itr->proposal_id); - - //if (qc_itr!=_qc_store.get().end()) _qc_store.get().erase(qc_itr); - _proposal_store.get().erase(itr); - - - } - - } - - void qc_chain::commit(hs_proposal_message proposal){ - -/* ilog("=== attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", proposal.block_num()) - ("proposal_id", proposal.proposal_id) - ("block_id", proposal.block_id) - ("phase_counter", proposal.phase_counter) - ("parent_id", proposal.parent_id)); - */ - bool sequence_respected = false; - - proposal_store_type::nth_index<0>::type::iterator last_exec_prop = _proposal_store.get().find( _b_exec ); - -/* ilog("=== _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", last_exec_prop->block_num()) - ("proposal_id", last_exec_prop->proposal_id) - ("block_id", last_exec_prop->block_id) - ("phase_counter", last_exec_prop->phase_counter) - ("parent_id", last_exec_prop->parent_id));*/ - - if (_b_exec==NULL_PROPOSAL_ID){ - //ilog("first block committed"); - sequence_respected = true; - } - else sequence_respected = last_exec_prop->get_height() < proposal.get_height(); - - if (sequence_respected){ - - proposal_store_type::nth_index<0>::type::iterator p_itr = _proposal_store.get().find( proposal.parent_id ); - - if (p_itr != _proposal_store.get().end()){ - - //ilog("=== recursively committing" ); - - commit(*p_itr); //recursively commit all non-committed ancestor blocks sequentially first - - } - - ilog("=== committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("block_id", proposal.block_id) - ("proposal_id", proposal.proposal_id)); - - } - - } - -}} - - From a3a372aac67ec15e6983cb86fd7ab943159a508a Mon Sep 17 00:00:00 2001 From: fcecin Date: Wed, 23 Aug 2023 13:31:02 -0300 Subject: [PATCH 054/151] Fix threading 1/2 (#1541) & qc_chain private: - Moved everything in qc_chain.hpp that is not an interface to private: - Fixed test_hotstuff to use get_state() instead of accessing various (now) private fields - Fixed test_pacemaker to use get_id() instead of accessing (now) private _id field - Added get_proposal() helper method to finalizer_state struct in chain/hotstuff.hpp since finalizer_state is now used in tests, etc. - Made qc_chain class lock-free; all thread synchronization is now done externally - Solved concurrency get_finalizer_state vs. qc_chain updates by caching chain_pacemaker::get_state(); zero overhead on qc_chain state updating, low overhead on external state read (no global/write locks acquired on cache hits) --- .../chain/include/eosio/chain/hotstuff.hpp | 7 + libraries/hotstuff/chain_pacemaker.cpp | 28 +- .../eosio/hotstuff/chain_pacemaker.hpp | 8 +- .../include/eosio/hotstuff/qc_chain.hpp | 114 ++-- libraries/hotstuff/qc_chain.cpp | 52 +- libraries/hotstuff/test/test_hotstuff.cpp | 540 ++++++++++-------- libraries/hotstuff/test/test_pacemaker.cpp | 8 +- 7 files changed, 422 insertions(+), 335 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 011e91d63d..11d3304809 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -68,6 +68,13 @@ namespace eosio::chain { eosio::chain::quorum_certificate current_qc; eosio::chain::extended_schedule schedule; map proposals; + + hs_proposal_message* get_proposal(const fc::sha256 &id) { + auto it = proposals.find(id); + if (it == proposals.end()) + return nullptr; + return & it->second; + } }; using hs_proposal_message_ptr = std::shared_ptr; diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 7ca5bdd50b..5d22fd4f4a 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -112,9 +112,31 @@ namespace eosio { namespace hotstuff { return _chain->is_builtin_activated( builtin_protocol_feature_t::instant_finality ); } - void chain_pacemaker::get_state( finalizer_state& fs ) const { - if (enabled()) - _qc_chain.get_state( fs ); // get_state() takes scare of finer-grained synchronization internally + void chain_pacemaker::get_state(finalizer_state& fs, bool force) const { + if (! enabled()) + return; + + // lock-free state version check + uint64_t current_state_version = _qc_chain.get_state_version(); + if (force || _state_cache_version != current_state_version) { + finalizer_state current_state; + { + csc prof("stat"); + std::lock_guard g( _hotstuff_global_mutex ); // lock IF engine to read state + prof.core_in(); + _qc_chain.get_state(current_state); + current_state_version = _qc_chain.get_state_version(); // get potentially fresher version + prof.core_out(); + } + { + std::unique_lock ul(_state_cache_mutex); // lock cache for writing + _state_cache = current_state; + _state_cache_version = current_state_version; + } + } + + std::shared_lock sl(_state_cache_mutex); // lock cache for reading + fs = _state_cache; } name chain_pacemaker::get_proposer() { diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index 02e2aff59b..c558d32f2d 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -23,7 +23,7 @@ namespace eosio::hotstuff { void on_hs_new_view_msg(const hs_new_view_message& msg); //new view msg event handler void on_hs_new_block_msg(const hs_new_block_message& msg); //new block msg event handler - void get_state( finalizer_state& fs ) const; + void get_state(finalizer_state& fs, bool force = false) const; //base_pacemaker interface functions @@ -54,7 +54,11 @@ namespace eosio::hotstuff { // These requests can come directly from the net threads, or indirectly from a // dedicated finalizer thread (TODO: discuss). #warning discuss - std::mutex _hotstuff_global_mutex; + mutable std::mutex _hotstuff_global_mutex; + + mutable finalizer_state _state_cache; + mutable std::shared_mutex _state_cache_mutex; + mutable uint64_t _state_cache_version = 0; chain::controller* _chain = nullptr; diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 0a59c0dcb3..b6611cdbed 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -21,6 +21,8 @@ #include #include +#include +#include // Enable this to swap the multi-index proposal store with std::map //#define QC_CHAIN_SIMPLE_PROPOSAL_STORE @@ -31,6 +33,8 @@ namespace eosio::hotstuff { using namespace boost::multi_index; using namespace eosio::chain; + // Concurrency note: qc_chain is a single-threaded and lock-free decision engine. + // All thread synchronization, if any, is external. class qc_chain { public: @@ -38,58 +42,28 @@ namespace eosio::hotstuff { qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, bool info_logging, bool error_logging); -#warning remove. bls12-381 key used for testing purposes - //todo : remove. bls12-381 key used for testing purposes - std::vector _seed = - { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, - 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, - 12, 62, 89, 110, 182, 9, 44, 20, 254, 22 }; - - fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); - - enum msg_type { - new_view = 1, - new_block = 2, - qc = 3, - vote = 4 - }; - - bool _chained_mode = false; - - fc::sha256 _b_leaf = NULL_PROPOSAL_ID; - fc::sha256 _b_lock = NULL_PROPOSAL_ID; - fc::sha256 _b_exec = NULL_PROPOSAL_ID; + uint64_t get_state_version() const { return _state_version; } // calling this w/ thread sync is optional - fc::sha256 _b_finality_violation = NULL_PROPOSAL_ID; - - block_id_type _block_exec = NULL_BLOCK_ID; + name get_id() const { return _id; } // so far, only ever relevant in a test environment (no sync) - block_id_type _pending_proposal_block = NULL_BLOCK_ID; + // Calls to the following methods should be thread-synchronized externally: - uint32_t _v_height = 0; + void get_state(finalizer_state& fs) const; - eosio::chain::quorum_certificate _high_qc; - eosio::chain::quorum_certificate _current_qc; - - eosio::chain::extended_schedule _schedule; - - name _id; - - base_pacemaker* _pacemaker = nullptr; + void on_beat(); //handler for pacemaker beat() - std::set _my_producers; + void on_hs_vote_msg(const hs_vote_message& msg); //vote msg event handler + void on_hs_proposal_msg(const hs_proposal_message& msg); //proposal msg event handler + void on_hs_new_view_msg(const hs_new_view_message& msg); //new view msg event handler + void on_hs_new_block_msg(const hs_new_block_message& msg); //new block msg event handler - bool _log = true; - bool _errors = true; + private: - // returns nullptr if not found - const hs_proposal_message* get_proposal(const fc::sha256& proposal_id); + const hs_proposal_message* get_proposal(const fc::sha256& proposal_id); // returns nullptr if not found // returns false if proposal with that same ID already exists at the store of its height bool insert_proposal(const hs_proposal_message& proposal); - void get_state( finalizer_state& fs ) const; - uint32_t positive_bits_count(fc::unsigned_int value); fc::unsigned_int update_bitset(fc::unsigned_int value, name finalizer); @@ -119,9 +93,7 @@ namespace eosio::hotstuff { bool extends(const fc::sha256& descendant, const fc::sha256& ancestor); //verify that a proposal descends from another - void on_beat(); //handler for pacemaker beat() - - void update_high_qc(const eosio::chain::quorum_certificate& high_qc); //check if update to our high qc is required + bool update_high_qc(const eosio::chain::quorum_certificate& high_qc); //check if update to our high qc is required void leader_rotation_check(); //check if leader rotation is required @@ -134,31 +106,45 @@ namespace eosio::hotstuff { void send_hs_new_view_msg(const hs_new_view_message& msg); //send new view msg void send_hs_new_block_msg(const hs_new_block_message& msg); //send new block msg - void on_hs_vote_msg(const hs_vote_message& msg); //vote msg event handler - void on_hs_proposal_msg(const hs_proposal_message& msg); //proposal msg event handler - void on_hs_new_view_msg(const hs_new_view_message& msg); //new view msg event handler - void on_hs_new_block_msg(const hs_new_block_message& msg); //new block msg event handler - void update(const hs_proposal_message& proposal); //update internal state void commit(const hs_proposal_message& proposal); //commit proposal (finality) void gc_proposals(uint64_t cutoff); //garbage collection of old proposals -private: - - // This mutex synchronizes all writes to the data members of this qc_chain against - // get_state() calls (which ultimately come from e.g. the HTTP plugin). - // This could result in a HTTP query that gets the state of the core while it is - // in the middle of processing a given request, since this is not serializing - // against high-level message or request processing borders. - // If that behavior is not desired, we can instead synchronize this against a - // consistent past snapshot of the qc_chain's state for e.g. the HTTP plugin, - // which would be updated at the end of processing every request to the core - // that does alter the qc_chain (hotstuff protocol state). - // And if the chain_pacemaker::_hotstuff_global_mutex locking strategy is ever - // changed, then this probably needs to be reviewed as well. - // - mutable std::mutex _state_mutex; +#warning remove. bls12-381 key used for testing purposes + //todo : remove. bls12-381 key used for testing purposes + std::vector _seed = + { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, + 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, + 12, 62, 89, 110, 182, 9, 44, 20, 254, 22 }; + + fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); + + enum msg_type { + new_view = 1, + new_block = 2, + qc = 3, + vote = 4 + }; + + bool _chained_mode = false; + block_id_type _block_exec = NULL_BLOCK_ID; + block_id_type _pending_proposal_block = NULL_BLOCK_ID; + fc::sha256 _b_leaf = NULL_PROPOSAL_ID; + fc::sha256 _b_lock = NULL_PROPOSAL_ID; + fc::sha256 _b_exec = NULL_PROPOSAL_ID; + fc::sha256 _b_finality_violation = NULL_PROPOSAL_ID; + eosio::chain::quorum_certificate _high_qc; + eosio::chain::quorum_certificate _current_qc; + uint32_t _v_height = 0; + eosio::chain::extended_schedule _schedule; + base_pacemaker* _pacemaker = nullptr; + std::set _my_producers; + bool _log = true; + bool _errors = true; + name _id; + + mutable uint64_t _state_version = 1; #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE // keep one proposal store (id -> proposal) by each height (height -> proposal store) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 22e5e6d1f2..96bed780a5 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -75,7 +75,6 @@ namespace eosio { namespace hotstuff { } bool qc_chain::insert_proposal(const hs_proposal_message & proposal) { - std::lock_guard g( _state_mutex ); #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE uint64_t proposal_height = proposal.get_height(); ps_height_iterator psh_it = _proposal_stores_by_height.find( proposal_height ); @@ -99,8 +98,7 @@ namespace eosio { namespace hotstuff { #endif } - void qc_chain::get_state( finalizer_state& fs ) const { - std::lock_guard g( _state_mutex ); + void qc_chain::get_state(finalizer_state& fs) const { fs.chained_mode = _chained_mode; fs.b_leaf = _b_leaf; fs.b_lock = _b_lock; @@ -238,7 +236,6 @@ namespace eosio { namespace hotstuff { } void qc_chain::reset_qc(const fc::sha256& proposal_id){ - std::lock_guard g( _state_mutex ); #ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); #endif @@ -347,10 +344,7 @@ namespace eosio { namespace hotstuff { } hs_vote_message qc_chain::sign_proposal(const hs_proposal_message & proposal, name finalizer){ - - std::unique_lock state_lock( _state_mutex ); _v_height = proposal.get_height(); - state_lock.unlock(); digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); @@ -497,6 +491,8 @@ namespace eosio { namespace hotstuff { //check for leader change leader_rotation_check(); + ++_state_version; + //auto total_time = fc::time_point::now() - start; //if (_log) ilog(" ... process_proposal() total time : ${total_time}", ("total_time", total_time)); } @@ -530,14 +526,12 @@ namespace eosio { namespace hotstuff { // If quorum is already met, we don't need to do anything else. Otherwise, we aggregate the signature. if (!quorum_met){ - std::unique_lock state_lock( _state_mutex ); if (_current_qc.active_finalizers>0) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); else _current_qc.active_agg_sig = vote.sig; _current_qc.active_finalizers = update_bitset(_current_qc.active_finalizers, vote.finalizer); - state_lock.unlock(); quorum_met = is_quorum_met(_current_qc, _schedule, *p); @@ -549,9 +543,7 @@ namespace eosio { namespace hotstuff { ("proposal_id", vote.proposal_id) ("id", _id)); - state_lock.lock(); _current_qc.quorum_met = true; - state_lock.unlock(); //ilog(" === update_high_qc : _current_qc ==="); update_high_qc(_current_qc); @@ -575,10 +567,8 @@ namespace eosio { namespace hotstuff { #ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); #endif - state_lock.lock(); _pending_proposal_block = NULL_BLOCK_ID; _b_leaf = proposal_candidate.proposal_id; - state_lock.unlock(); send_hs_proposal_msg(proposal_candidate); #ifdef QC_CHAIN_TRACE_DEBUG @@ -586,6 +576,8 @@ namespace eosio { namespace hotstuff { #endif } } + + ++_state_version; } //auto total_time = fc::time_point::now() - start; @@ -596,7 +588,9 @@ namespace eosio { namespace hotstuff { #ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", msg.high_qc)("id", _id)); #endif - update_high_qc(msg.high_qc); + if (update_high_qc(msg.high_qc)) { + ++_state_version; + } } void qc_chain::process_new_block(const hs_new_block_message & msg){ @@ -636,9 +630,7 @@ namespace eosio { namespace hotstuff { ("quorum_met", _current_qc.quorum_met)); if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", msg.block_id)); #endif - std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = msg.block_id; - state_lock.unlock(); } else { @@ -655,10 +647,8 @@ namespace eosio { namespace hotstuff { #ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_new_block)", ("id", _id)); #endif - std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = NULL_BLOCK_ID; _b_leaf = proposal_candidate.proposal_id; - state_lock.unlock(); send_hs_proposal_msg(proposal_candidate); @@ -666,6 +656,8 @@ namespace eosio { namespace hotstuff { if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); #endif } + + ++_state_version; } void qc_chain::send_hs_proposal_msg(const hs_proposal_message & msg){ @@ -773,7 +765,8 @@ namespace eosio { namespace hotstuff { } } - void qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ + // returns true on state change (caller decides update on state version + bool qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ #ifdef QC_CHAIN_TRACE_DEBUG ilog(" === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); @@ -783,21 +776,20 @@ namespace eosio { namespace hotstuff { if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ - std::unique_lock state_lock( _state_mutex ); _high_qc = high_qc; _b_leaf = _high_qc.proposal_id; - state_lock.unlock(); #ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); #endif + return true; } else { const hs_proposal_message *old_high_qc_prop = get_proposal( _high_qc.proposal_id ); const hs_proposal_message *new_high_qc_prop = get_proposal( high_qc.proposal_id ); if (old_high_qc_prop == nullptr) - return; + return false; if (new_high_qc_prop == nullptr) - return; + return false; if (new_high_qc_prop->get_height() > old_high_qc_prop->get_height() && is_quorum_met(high_qc, _schedule, *new_high_qc_prop)) @@ -808,21 +800,20 @@ namespace eosio { namespace hotstuff { #ifdef QC_CHAIN_TRACE_DEBUG ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); #endif - std::unique_lock state_lock( _state_mutex ); _high_qc = high_qc; _high_qc.quorum_met = true; _b_leaf = _high_qc.proposal_id; - state_lock.unlock(); #ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); #endif + return true; } } + return false; } void qc_chain::leader_rotation_check(){ - //verify if leader changed name current_leader = _pacemaker->get_leader(); @@ -843,9 +834,7 @@ namespace eosio { namespace hotstuff { if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); #endif - std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = NULL_BLOCK_ID; - state_lock.unlock(); hs_new_view_message new_view; @@ -1034,9 +1023,7 @@ namespace eosio { namespace hotstuff { #ifdef QC_CHAIN_TRACE_DEBUG ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); #endif - std::unique_lock state_lock( _state_mutex ); _b_lock = b_1.proposal_id; //commit phase on b1 - state_lock.unlock(); #ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); @@ -1078,9 +1065,7 @@ namespace eosio { namespace hotstuff { ("proposal_id_1", b.proposal_id) ("proposal_id_2", b_exec->proposal_id)); - std::unique_lock state_lock( _state_mutex ); _b_finality_violation = b.proposal_id; - state_lock.unlock(); //protocol failure return; @@ -1093,10 +1078,8 @@ namespace eosio { namespace hotstuff { ilog(" === last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); #endif - std::unique_lock state_lock( _state_mutex ); _b_exec = b.proposal_id; //decide phase on b _block_exec = b.block_id; - state_lock.unlock(); gc_proposals( b.get_height()-1); } @@ -1110,7 +1093,6 @@ namespace eosio { namespace hotstuff { void qc_chain::gc_proposals(uint64_t cutoff){ //ilog(" === garbage collection on old data"); - std::lock_guard g( _state_mutex ); #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE ps_height_iterator psh_it = _proposal_stores_by_height.begin(); while (psh_it != _proposal_stores_by_height.end()) { diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 75c583c098..9ab1e7f580 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -112,7 +112,7 @@ class hotstuff_test_handler { std::cout << "\n"; } - void print_bp_state(name bp, std::string message){ + void print_bp_state(name bp, std::string message) const { std::cout << "\n"; std::cout << message; @@ -121,21 +121,24 @@ class hotstuff_test_handler { auto qcc_entry = std::find_if(_qc_chains.begin(), _qc_chains.end(), [&](const auto& q){ return q.first == bp; }); qc_chain & qcc = *qcc_entry->second.get(); - const hs_proposal_message *leaf = qcc.get_proposal( qcc._b_leaf ); - const hs_proposal_message *qc = qcc.get_proposal( qcc._high_qc.proposal_id ); - const hs_proposal_message *lock = qcc.get_proposal( qcc._b_lock ); - const hs_proposal_message *exec = qcc.get_proposal( qcc._b_exec ); - if (leaf != nullptr) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << qcc._b_leaf.str() << " block_num : " << leaf->block_num() << ", phase : " << unsigned(leaf->phase_counter) << "\n"; + finalizer_state fs; + qcc.get_state(fs); + const hs_proposal_message *leaf = fs.get_proposal( fs.b_leaf ); + const hs_proposal_message *qc = fs.get_proposal( fs.high_qc.proposal_id ); + const hs_proposal_message *lock = fs.get_proposal( fs.b_lock ); + const hs_proposal_message *exec = fs.get_proposal( fs.b_exec ); + + if (leaf != nullptr) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << fs.b_leaf.str() << " block_num : " << leaf->block_num() << ", phase : " << unsigned(leaf->phase_counter) << "\n"; else std::cout << " - No b_leaf value " << "\n"; - if (qc != nullptr) std::cout << " - " << bp.to_string() << " current high_qc is : " << qcc._high_qc.proposal_id.str() << " block_num : " << qc->block_num() << ", phase : " << unsigned(qc->phase_counter) << "\n"; + if (qc != nullptr) std::cout << " - " << bp.to_string() << " current high_qc is : " << fs.high_qc.proposal_id.str() << " block_num : " << qc->block_num() << ", phase : " << unsigned(qc->phase_counter) << "\n"; else std::cout << " - No high_qc value " << "\n"; - if (lock != nullptr) std::cout << " - " << bp.to_string() << " current _b_lock is : " << qcc._b_lock.str() << " block_num : " << lock->block_num() << ", phase : " << unsigned(lock->phase_counter) << "\n"; + if (lock != nullptr) std::cout << " - " << bp.to_string() << " current _b_lock is : " << fs.b_lock.str() << " block_num : " << lock->block_num() << ", phase : " << unsigned(lock->phase_counter) << "\n"; else std::cout << " - No b_lock value " << "\n"; - if (exec != nullptr) std::cout << " - " << bp.to_string() << " current _b_exec is : " << qcc._b_exec.str() << " block_num : " << exec->block_num() << ", phase : " << unsigned(exec->phase_counter) << "\n"; + if (exec != nullptr) std::cout << " - " << bp.to_string() << " current _b_exec is : " << fs.b_exec.str() << " block_num : " << exec->block_num() << ", phase : " << unsigned(exec->phase_counter) << "\n"; else std::cout << " - No b_exec value " << "\n"; std::cout << "\n"; @@ -191,7 +194,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { tpm.set_finalizers(unique_replicas); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + finalizer_state fs_bpa; + qcc_bpa->second->get_state(fs_bpa); auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + finalizer_state fs_bpb; + qcc_bpb->second->get_state(fs_bpb); ht.print_bp_state("bpa"_n, ""); @@ -203,37 +210,41 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on first block) tpm.dispatch(""); //send proposal to replicas (precommit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) tpm.dispatch(""); //send proposal to replicas (commit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //propagating votes on new proposal (commitQC on first block) tpm.dispatch(""); //send proposal to replicas (decide on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //propagating votes on new proposal (decide on first block) @@ -243,51 +254,57 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { tpm.dispatch(""); //send proposal to replicas (prepare on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); tpm.dispatch(""); //send votes on proposal (prepareQC on second block) tpm.dispatch(""); //send proposal to replicas (precommit on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) tpm.dispatch(""); //send proposal to replicas (commit on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) tpm.dispatch(""); //send proposal to replicas (decide on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); tpm.dispatch(""); //send proposal to replicas (decide on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); //check bpb as well - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); } FC_LOG_AND_RETHROW(); @@ -307,7 +324,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.set_finalizers(unique_replicas); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + finalizer_state fs_bpa; + qcc_bpa->second->get_state(fs_bpa); auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + finalizer_state fs_bpb; + qcc_bpb->second->get_state(fs_bpb); tpm.set_current_block_id(ids[0]); //first block @@ -315,19 +336,21 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.dispatch(""); //send proposal to replicas (prepare on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on first block) tpm.dispatch(""); //send proposal to replicas (precommit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.set_current_block_id(ids[1]); //second block @@ -335,19 +358,21 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.dispatch(""); //send proposal to replicas (prepare on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on second block) tpm.dispatch(""); //send proposal to replicas (precommit on second block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.set_current_block_id(ids[2]); //second block @@ -355,26 +380,29 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { tpm.dispatch(""); //propagating votes on new proposal (prepare on third block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //send votes on proposal (prepareQC on third block) tpm.dispatch(""); //propagating votes on new proposal (precommitQC on third block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); //check bpb as well - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); } FC_LOG_AND_RETHROW(); @@ -394,8 +422,14 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.set_finalizers(unique_replicas); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + finalizer_state fs_bpa; + qcc_bpa->second->get_state(fs_bpa); auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + finalizer_state fs_bpb; + qcc_bpb->second->get_state(fs_bpb); auto qcc_bpc = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpc"_n; }); + finalizer_state fs_bpc; + qcc_bpc->second->get_state(fs_bpc); tpm.set_current_block_id(ids[0]); //first block @@ -403,28 +437,31 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.dispatch(""); //send proposal to replicas (prepare on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on first block) tpm.dispatch(""); //send proposal to replicas (precommit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) tpm.dispatch(""); //send proposal to replicas (commit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.set_next_leader("bpb"_n); //leader is set to rotate on next block @@ -432,10 +469,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.dispatch(""); //send proposal to replicas (decide on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //propagating votes on new proposal (decide on first block) @@ -448,49 +486,55 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { tpm.dispatch(""); //send proposal to replicas (prepare on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //send votes on proposal (prepareQC on second block) tpm.dispatch(""); //send proposal to replicas (precommit on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) tpm.dispatch(""); //send proposal to replicas (commit on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) tpm.dispatch(""); //send proposal to replicas (decide on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpa as well - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpc as well - BOOST_CHECK_EQUAL(qcc_bpc->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpc->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpc->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + qcc_bpc->second->get_state(fs_bpc); + BOOST_CHECK_EQUAL(fs_bpc.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpc.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpc.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); } FC_LOG_AND_RETHROW(); @@ -510,8 +554,14 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { tpm.set_finalizers(unique_replicas); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + finalizer_state fs_bpa; + qcc_bpa->second->get_state(fs_bpa); auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + finalizer_state fs_bpb; + qcc_bpb->second->get_state(fs_bpb); auto qcc_bpi = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpi"_n; }); + finalizer_state fs_bpi; + qcc_bpi->second->get_state(fs_bpi); tpm.set_current_block_id(ids[0]); //first block @@ -519,19 +569,21 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { tpm.dispatch(""); //send proposal to replicas (prepare on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on first block) tpm.dispatch(""); //send proposal to replicas (precommit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) @@ -547,10 +599,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { tpm.dispatch(""); //send proposal to replicas (commit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.set_next_leader("bpi"_n); //leader is set to rotate on next block @@ -558,10 +611,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, "before reactivate"); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.activate("bpb"_n); tpm.activate("bpc"_n); @@ -583,30 +637,33 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpi"_n, ""); //ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on second block) tpm.dispatch(""); //send proposal to replicas (precommit on second block) //ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) tpm.dispatch(""); //send proposal to replicas (commit on second block) //ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) @@ -614,23 +671,26 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); //ht.print_bp_state("bpb"_n, ""); //check bpa as well - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); //ht.print_bp_state("bpi"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpi->second->_high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(qcc_bpi->second->_b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(qcc_bpi->second->_b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + qcc_bpi->second->get_state(fs_bpi); + BOOST_CHECK_EQUAL(fs_bpi.high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpi.b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpi.b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); } FC_LOG_AND_RETHROW(); @@ -699,6 +759,8 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { tpm2.set_finalizers(replica_set_2); auto qcc_bpe = std::find_if(ht1._qc_chains.begin(), ht1._qc_chains.end(), [&](const auto& q){ return q.first == "bpe"_n; }); + finalizer_state fs_bpe; + qcc_bpe->second->get_state(fs_bpe); //auto qcc_bpf = std::find_if(ht2._qc_chains.begin(), ht2._qc_chains.end(), [&](const auto& q){ return q.first == "bpf"_n; }); std::vector msgs; @@ -717,10 +779,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpe->second->get_state(fs_bpe); + BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm1.dispatch(""); tpm1.dispatch(""); @@ -730,10 +793,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpe->second->get_state(fs_bpe); + BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm1.dispatch(""); tpm1.dispatch(""); @@ -743,10 +807,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpe->second->get_state(fs_bpe); + BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm1.dispatch(""); tpm1.dispatch(""); @@ -756,10 +821,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpe->second->get_state(fs_bpe); + BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm1.set_current_block_id(ids[1]); //first block tpm2.set_current_block_id(alternate_ids[1]); //first block @@ -775,10 +841,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + qcc_bpe->second->get_state(fs_bpe); + BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); tpm1.pipe(tpm2.dispatch("")); tpm1.dispatch(""); @@ -788,10 +855,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + qcc_bpe->second->get_state(fs_bpe); + BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); tpm1.pipe(tpm2.dispatch("")); tpm1.dispatch(""); @@ -801,10 +869,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + qcc_bpe->second->get_state(fs_bpe); + BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); tpm1.pipe(tpm2.dispatch("")); tpm1.dispatch(""); @@ -814,12 +883,13 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { //ht1.print_bp_state("bpe"_n, ""); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + qcc_bpe->second->get_state(fs_bpe); + BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(qcc_bpe->second->_b_finality_violation.str(), std::string("5585accc44c753636d1381067c7f915d7fff2d33846aae04820abc055d952860")); + BOOST_CHECK_EQUAL(fs_bpe.b_finality_violation.str(), std::string("5585accc44c753636d1381067c7f915d7fff2d33846aae04820abc055d952860")); } FC_LOG_AND_RETHROW(); @@ -839,8 +909,14 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { tpm.set_finalizers(unique_replicas); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); + finalizer_state fs_bpa; + qcc_bpa->second->get_state(fs_bpa); auto qcc_bpb = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpb"_n; }); + finalizer_state fs_bpb; + qcc_bpb->second->get_state(fs_bpb); auto qcc_bpc = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpc"_n; }); + finalizer_state fs_bpc; + qcc_bpc->second->get_state(fs_bpc); tpm.set_current_block_id(ids[0]); //first block @@ -850,28 +926,31 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { tpm.dispatch(""); //send proposal to replicas (prepare on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //send votes on proposal (prepareQC on first block) tpm.dispatch(""); //send proposal to replicas (precommit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) tpm.dispatch(""); //send proposal to replicas (commit on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); tpm.set_next_leader("bpb"_n); //leader is set to rotate on next block @@ -879,10 +958,11 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { tpm.dispatch(""); //send proposal to replicas (decide on first block) - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //propagating votes on new proposal (decide on first block) @@ -897,49 +977,55 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { tpm.dispatch(""); //send proposal to replicas (prepare on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); tpm.dispatch(""); //send votes on proposal (prepareQC on second block) tpm.dispatch(""); //send proposal to replicas (precommit on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); tpm.dispatch(""); //propagating votes on new proposal (precommitQC on second block) tpm.dispatch(""); //send proposal to replicas (commit on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); tpm.dispatch(""); //propagating votes on new proposal (commitQC on second block) tpm.dispatch(""); //send proposal to replicas (decide on second block) - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpb->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + qcc_bpb->second->get_state(fs_bpb); + BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpa as well - BOOST_CHECK_EQUAL(qcc_bpa->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + qcc_bpa->second->get_state(fs_bpa); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpc as well - BOOST_CHECK_EQUAL(qcc_bpc->second->_high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(qcc_bpc->second->_b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(qcc_bpc->second->_b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + qcc_bpc->second->get_state(fs_bpc); + BOOST_CHECK_EQUAL(fs_bpc.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpc.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpc.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(qcc_bpa->second->_b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.b_finality_violation.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); } FC_LOG_AND_RETHROW(); diff --git a/libraries/hotstuff/test/test_pacemaker.cpp b/libraries/hotstuff/test/test_pacemaker.cpp index ff21284a6f..a35f7ea0c3 100644 --- a/libraries/hotstuff/test/test_pacemaker.cpp +++ b/libraries/hotstuff/test/test_pacemaker.cpp @@ -179,7 +179,7 @@ namespace eosio::hotstuff { while (qc_itr != _qcc_store.end()){ const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->_id != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id() != id && is_qc_chain_active(qcc_name) ) qcc_ptr->on_hs_proposal_msg(msg); qc_itr++; } @@ -190,7 +190,7 @@ namespace eosio::hotstuff { while (qc_itr != _qcc_store.end()) { const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->_id != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id() != id && is_qc_chain_active(qcc_name) ) qcc_ptr->on_hs_vote_msg(msg); qc_itr++; } @@ -201,7 +201,7 @@ namespace eosio::hotstuff { while (qc_itr != _qcc_store.end()) { const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->_id != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id() != id && is_qc_chain_active(qcc_name) ) qcc_ptr->on_hs_new_block_msg(msg); qc_itr++; } @@ -212,7 +212,7 @@ namespace eosio::hotstuff { while (qc_itr != _qcc_store.end()){ const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->_id != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id() != id && is_qc_chain_active(qcc_name) ) qcc_ptr->on_hs_new_view_msg(msg); qc_itr++; } From 479f0c9368f9112d3016177f8323d15619c81945 Mon Sep 17 00:00:00 2001 From: fcecin Date: Wed, 23 Aug 2023 16:19:29 -0300 Subject: [PATCH 055/151] Atomic version counter, cleanup & clarity - std::atomic<> _state_version & _state_cache_version - doc _state_cache_version mutex - qc_chain::get_id() renamed to get_id_i() - remove mutex includes from qc_chain.hpp --- libraries/hotstuff/chain_pacemaker.cpp | 4 ++-- .../include/eosio/hotstuff/chain_pacemaker.hpp | 12 ++++++++---- .../hotstuff/include/eosio/hotstuff/qc_chain.hpp | 7 ++----- libraries/hotstuff/test/test_pacemaker.cpp | 8 ++++---- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 5d22fd4f4a..65729e5caa 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -112,13 +112,13 @@ namespace eosio { namespace hotstuff { return _chain->is_builtin_activated( builtin_protocol_feature_t::instant_finality ); } - void chain_pacemaker::get_state(finalizer_state& fs, bool force) const { + void chain_pacemaker::get_state(finalizer_state& fs) const { if (! enabled()) return; // lock-free state version check uint64_t current_state_version = _qc_chain.get_state_version(); - if (force || _state_cache_version != current_state_version) { + if (_state_cache_version != current_state_version) { finalizer_state current_state; { csc prof("stat"); diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index c558d32f2d..750b49bdff 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -3,6 +3,8 @@ #include #include +#include + namespace eosio::chain { class controller; } @@ -23,7 +25,7 @@ namespace eosio::hotstuff { void on_hs_new_view_msg(const hs_new_view_message& msg); //new view msg event handler void on_hs_new_block_msg(const hs_new_block_message& msg); //new block msg event handler - void get_state(finalizer_state& fs, bool force = false) const; + void get_state(finalizer_state& fs) const; //base_pacemaker interface functions @@ -56,9 +58,11 @@ namespace eosio::hotstuff { #warning discuss mutable std::mutex _hotstuff_global_mutex; - mutable finalizer_state _state_cache; - mutable std::shared_mutex _state_cache_mutex; - mutable uint64_t _state_cache_version = 0; + // _state_cache_mutex provides a R/W lock over _state_cache and _state_cache_version, + // which implement a cache of the finalizer_state (_qc_chain::get_state()). + mutable std::shared_mutex _state_cache_mutex; + mutable finalizer_state _state_cache; + mutable std::atomic _state_cache_version = 0; chain::controller* _chain = nullptr; diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index b6611cdbed..4ad6a7f643 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -21,9 +21,6 @@ #include #include -#include -#include - // Enable this to swap the multi-index proposal store with std::map //#define QC_CHAIN_SIMPLE_PROPOSAL_STORE @@ -44,7 +41,7 @@ namespace eosio::hotstuff { uint64_t get_state_version() const { return _state_version; } // calling this w/ thread sync is optional - name get_id() const { return _id; } // so far, only ever relevant in a test environment (no sync) + name get_id_i() const { return _id; } // so far, only ever relevant in a test environment (no sync) // Calls to the following methods should be thread-synchronized externally: @@ -144,7 +141,7 @@ namespace eosio::hotstuff { bool _errors = true; name _id; - mutable uint64_t _state_version = 1; + mutable std::atomic _state_version = 1; #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE // keep one proposal store (id -> proposal) by each height (height -> proposal store) diff --git a/libraries/hotstuff/test/test_pacemaker.cpp b/libraries/hotstuff/test/test_pacemaker.cpp index a35f7ea0c3..de42e32ff1 100644 --- a/libraries/hotstuff/test/test_pacemaker.cpp +++ b/libraries/hotstuff/test/test_pacemaker.cpp @@ -179,7 +179,7 @@ namespace eosio::hotstuff { while (qc_itr != _qcc_store.end()){ const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->get_id() != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ) qcc_ptr->on_hs_proposal_msg(msg); qc_itr++; } @@ -190,7 +190,7 @@ namespace eosio::hotstuff { while (qc_itr != _qcc_store.end()) { const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->get_id() != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ) qcc_ptr->on_hs_vote_msg(msg); qc_itr++; } @@ -201,7 +201,7 @@ namespace eosio::hotstuff { while (qc_itr != _qcc_store.end()) { const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->get_id() != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ) qcc_ptr->on_hs_new_block_msg(msg); qc_itr++; } @@ -212,7 +212,7 @@ namespace eosio::hotstuff { while (qc_itr != _qcc_store.end()){ const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->get_id() != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ) qcc_ptr->on_hs_new_view_msg(msg); qc_itr++; } From d4b3e3efe1a45edeb0bef3b796e84c9dadb93380 Mon Sep 17 00:00:00 2001 From: fcecin Date: Wed, 23 Aug 2023 16:40:42 -0300 Subject: [PATCH 056/151] fix const type& arg --- libraries/chain/include/eosio/chain/hotstuff.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 11d3304809..00f236d27d 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -69,7 +69,7 @@ namespace eosio::chain { eosio::chain::extended_schedule schedule; map proposals; - hs_proposal_message* get_proposal(const fc::sha256 &id) { + hs_proposal_message* get_proposal(const fc::sha256& id) { auto it = proposals.find(id); if (it == proposals.end()) return nullptr; From 4db2e1b07cb45a17b036d6f8460b313f30c036f4 Mon Sep 17 00:00:00 2001 From: fcecin Date: Wed, 23 Aug 2023 18:41:29 -0300 Subject: [PATCH 057/151] scoped_exit for state_version & const - Using fc::make_scoped_exit to increment state_version in qc_chain - const correct finalizer_state::get_proposal() --- libraries/chain/include/eosio/chain/hotstuff.hpp | 2 +- libraries/hotstuff/qc_chain.cpp | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 00f236d27d..e51d6968fb 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -69,7 +69,7 @@ namespace eosio::chain { eosio::chain::extended_schedule schedule; map proposals; - hs_proposal_message* get_proposal(const fc::sha256& id) { + const hs_proposal_message* get_proposal(const fc::sha256& id) const { auto it = proposals.find(id); if (it == proposals.end()) return nullptr; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 96bed780a5..7d690b678e 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -1,5 +1,7 @@ #include +#include + /* Todo list / notes: @@ -434,6 +436,8 @@ namespace eosio { namespace hotstuff { bool success = insert_proposal( proposal ); EOS_ASSERT( success , chain_exception, "internal error: duplicate proposal insert attempt" ); // can't happen unless bad mutex somewhere; already checked for this + auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); // assert failing above would mean no change + //if I am a finalizer for this proposal and the safenode predicate for a possible vote is true, sign bool am_finalizer = am_i_finalizer(); bool node_safe = is_node_safe(proposal); @@ -491,8 +495,6 @@ namespace eosio { namespace hotstuff { //check for leader change leader_rotation_check(); - ++_state_version; - //auto total_time = fc::time_point::now() - start; //if (_log) ilog(" ... process_proposal() total time : ${total_time}", ("total_time", total_time)); } @@ -526,6 +528,8 @@ namespace eosio { namespace hotstuff { // If quorum is already met, we don't need to do anything else. Otherwise, we aggregate the signature. if (!quorum_met){ + auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); + if (_current_qc.active_finalizers>0) _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); else @@ -576,8 +580,6 @@ namespace eosio { namespace hotstuff { #endif } } - - ++_state_version; } //auto total_time = fc::time_point::now() - start; @@ -589,7 +591,7 @@ namespace eosio { namespace hotstuff { if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", msg.high_qc)("id", _id)); #endif if (update_high_qc(msg.high_qc)) { - ++_state_version; + ++_state_version; // should be OK; update_high_qc() should not throw } } @@ -621,6 +623,8 @@ namespace eosio { namespace hotstuff { // // ------------------------------------------------------------------ + auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); + if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false) { #ifdef QC_CHAIN_TRACE_DEBUG @@ -656,8 +660,6 @@ namespace eosio { namespace hotstuff { if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); #endif } - - ++_state_version; } void qc_chain::send_hs_proposal_msg(const hs_proposal_message & msg){ From a1ced9cf44f7a956056a9212cf99cd5a3cc0ec1d Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Wed, 23 Aug 2023 21:45:11 +0000 Subject: [PATCH 058/151] Added back prefixes for bls_private_key, bls_public_key and bls_signature --- .../include/fc/crypto/bls_private_key.hpp | 11 +++- .../include/fc/crypto/bls_public_key.hpp | 15 +++-- .../libfc/include/fc/crypto/bls_signature.hpp | 42 +++--------- .../libfc/src/crypto/bls_private_key.cpp | 64 ++++++------------- libraries/libfc/src/crypto/bls_public_key.cpp | 36 +++++++---- libraries/libfc/src/crypto/bls_signature.cpp | 35 ++++++---- libraries/libfc/test/test_bls.cpp | 4 +- 7 files changed, 99 insertions(+), 108 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index c28ef57965..56bcdd49c0 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -5,6 +5,11 @@ namespace fc::crypto::blslib { + namespace config { + constexpr const char* bls_private_key_base_prefix = "PVT"; + constexpr const char* bls_private_key_prefix = "BLS"; + }; + class bls_private_key { public: @@ -20,7 +25,7 @@ namespace fc::crypto::blslib { // serialize to/from string // TODO: determine format to use for string of private key explicit bls_private_key(const string& base58str); - std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; + std::string to_string(const yield_function_t& yield = yield_function_t()) const; bls_public_key get_public_key() const; bls_signature sign( const vector& message ) const; @@ -40,9 +45,9 @@ namespace fc::crypto::blslib { } // fc::crypto::blslib namespace fc { - void to_variant(const crypto::blslib::bls_private_key& var, variant& vo, const fc::yield_function_t& yield = fc::yield_function_t()); + void to_variant(const crypto::blslib::bls_private_key& var, variant& vo, const yield_function_t& yield = yield_function_t()); void from_variant(const variant& var, crypto::blslib::bls_private_key& vo); } // namespace fc -FC_REFLECT(fc::crypto::blslib::bls_private_key, (_seed) ) +FC_REFLECT(crypto::blslib::bls_private_key, (_seed) ) diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index d8bf0fbee1..93535249d7 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -8,10 +8,15 @@ #include #include -namespace fc { namespace crypto { namespace blslib { +namespace fc::crypto::blslib { using namespace std; + namespace config { + constexpr const char* bls_public_key_base_prefix = "PUB"; + constexpr const char* bls_public_key_prefix = "BLS"; + }; + class bls_public_key { public: @@ -28,7 +33,7 @@ namespace fc { namespace crypto { namespace blslib { // serialize to/from string explicit bls_public_key(const string& base58str); - std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; + std::string to_string(const yield_function_t& yield = yield_function_t()) const; //storage_type _storage; bls12_381::g1 _pkey; @@ -41,13 +46,13 @@ namespace fc { namespace crypto { namespace blslib { friend class bls_private_key; }; // bls_public_key -} } } // fc::crypto::blslib +} // fc::crypto::blslib namespace fc { - void to_variant(const crypto::blslib::bls_public_key& var, variant& vo, const fc::yield_function_t& yield = fc::yield_function_t()); + void to_variant(const crypto::blslib::bls_public_key& var, variant& vo, const yield_function_t& yield = yield_function_t()); void from_variant(const variant& var, crypto::blslib::bls_public_key& vo); } // namespace fc FC_REFLECT(bls12_381::g1, (x)(y)(z)) -FC_REFLECT(fc::crypto::blslib::bls_public_key, (_pkey) ) +FC_REFLECT(crypto::blslib::bls_public_key, (_pkey) ) diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index fce491e9c0..58390ce388 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -8,8 +8,7 @@ #include #include - -namespace fc { namespace crypto { namespace blslib { +namespace fc::crypto::blslib { using namespace std; @@ -21,7 +20,6 @@ namespace fc { namespace crypto { namespace blslib { class bls_signature { public: - //using storage_type = ecc::signature_shim;//std::variant; bls_signature() = default; bls_signature( bls_signature&& ) = default; @@ -32,59 +30,39 @@ namespace fc { namespace crypto { namespace blslib { _sig = sig; } -/* bls_signature( G2Element sig ){ - _sig = sig.Serialize(); - } -*/ // serialize to/from string explicit bls_signature(const string& base58str); - std::string to_string(const fc::yield_function_t& yield = fc::yield_function_t()) const; - -// size_t which() const; - - //size_t variable_size() const; + std::string to_string(const yield_function_t& yield = yield_function_t()) const; bls12_381::g2 _sig; private: - //storage_type _storage; - -/* bls_signature( storage_type&& other_storage ) - :_storage(std::forward(other_storage)) - {} -*/ - //friend bool operator == ( const bls_signature& p1, const bls_signature& p2); - //friend bool operator != ( const bls_signature& p1, const bls_signature& p2); - //friend bool operator < ( const bls_signature& p1, const bls_signature& p2); - //friend std::size_t hash_value(const bls_signature& b); //not cryptographic; for containers friend bool operator == ( const bls_signature& p1, const bls_signature& p2); friend struct reflector; friend class bls_private_key; friend class bls_public_key; - }; // bls_public_key - - //size_t hash_value(const bls_signature& b); + }; // bls_signature -} } } // fc::crypto::blslib +} // fc::crypto::blslib namespace fc { - void to_variant(const crypto::blslib::bls_signature& var, variant& vo, const fc::yield_function_t& yield = fc::yield_function_t()); + void to_variant(const crypto::blslib::bls_signature& var, variant& vo, const yield_function_t& yield = yield_function_t()); void from_variant(const variant& var, crypto::blslib::bls_signature& vo); } // namespace fc -namespace std { - template <> struct hash { - std::size_t operator()(const fc::crypto::blslib::bls_signature& k) const { +/*namespace std { + template <> struct hash { + std::size_t operator()(const crypto::blslib::bls_signature& k) const { //return fc::crypto::hash_value(k); return 0; } }; -} // std +} // std*/ FC_REFLECT(bls12_381::fp, (d)) FC_REFLECT(bls12_381::fp2, (c0)(c1)) FC_REFLECT(bls12_381::g2, (x)(y)(z)) -FC_REFLECT(fc::crypto::blslib::bls_signature, (_sig) ) +FC_REFLECT(crypto::blslib::bls_signature, (_sig) ) diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index 6cce1a3266..b6c19fd688 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace fc::crypto::blslib { @@ -25,78 +26,55 @@ namespace fc::crypto::blslib { return bls_private_key(v); } - string to_wif(vector secret, const fc::yield_function_t& yield ) - { - FC_ASSERT(secret.size() == 32); - - std::array v2; - - std::copy(secret.begin(), secret.end(), v2.begin()); + static vector priv_parse_base58(const string& base58str) + { - const size_t size_of_data_to_hash = 32 + 1; - const size_t size_of_hash_bytes = 4; - char data[size_of_data_to_hash + size_of_hash_bytes]; - data[0] = (char)0x80; // this is the Bitcoin MainNet code - memcpy(&data[1], (const char*)&v2, 32); - sha256 digest = sha256::hash(data, size_of_data_to_hash); - digest = sha256::hash(digest); - memcpy(data + size_of_data_to_hash, (char*)&digest, size_of_hash_bytes); + const auto pivot = base58str.find('_'); + FC_ASSERT(pivot != std::string::npos, "No delimiter in string, cannot determine data type: ${str}", ("str", base58str)); - return to_base58(data, sizeof(data), yield); - } + const auto base_prefix_str = base58str.substr(0, 3); + FC_ASSERT(config::bls_private_key_base_prefix == base_prefix_str, "BLS Private Key has invalid base prefix: ${str}", ("str", base58str)("base_prefix_str", base_prefix_str)); + + const auto prefix_str = base58str.substr(pivot + 1, 3); + FC_ASSERT(config::bls_private_key_prefix == prefix_str, "BLS Private Key has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str)); - std::vector from_wif( const string& wif_key ) - { - auto wif_bytes = from_base58(wif_key); - FC_ASSERT(wif_bytes.size() >= 5); + auto data_str = base58str.substr(8); - auto key_bytes = vector(wif_bytes.begin() + 1, wif_bytes.end() - 4); - fc::sha256 check = fc::sha256::hash(wif_bytes.data(), wif_bytes.size() - 4); - fc::sha256 check2 = fc::sha256::hash(check); + auto bytes = from_base58(data_str); - FC_ASSERT(memcmp( (char*)&check, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 || - memcmp( (char*)&check2, wif_bytes.data() + wif_bytes.size() - 4, 4 ) == 0 ); + FC_ASSERT(bytes.size() == 32 ); std::vector v2(32); - std::copy(key_bytes.begin(), key_bytes.end(), v2.begin()); + std::copy(bytes.begin(), bytes.end(), v2.begin()); return v2; } - static vector priv_parse_base58(const string& base58str) - { - //cout << base58str << "\n"; - - return from_wif(base58str); - } - bls_private_key::bls_private_key(const std::string& base58str) :_seed(priv_parse_base58(base58str)) {} - std::string bls_private_key::to_string(const fc::yield_function_t& yield) const + std::string bls_private_key::to_string(const yield_function_t& yield) const { - FC_ASSERT(_seed.size() == 32); - string wif = to_wif(_seed, yield); - - //cout << wif << "\n"; + string pk = to_base58((const char*)&(_seed[0]), 32, yield); - return wif; + return std::string(config::bls_private_key_base_prefix) + "_" + std::string(config::bls_private_key_prefix) + "_" + pk; + } } // fc::crypto::blslib namespace fc { - void to_variant(const fc::crypto::blslib::bls_private_key& var, variant& vo, const fc::yield_function_t& yield) + void to_variant(const crypto::blslib::bls_private_key& var, variant& vo, const yield_function_t& yield) { vo = var.to_string(yield); } - void from_variant(const variant& var, fc::crypto::blslib::bls_private_key& vo) + void from_variant(const variant& var, crypto::blslib::bls_private_key& vo) { - vo = fc::crypto::blslib::bls_private_key(var.as_string()); + vo = crypto::blslib::bls_private_key(var.as_string()); } } // fc diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 29ac4f681f..865d96cf82 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -2,16 +2,28 @@ #include #include -namespace fc { namespace crypto { namespace blslib { +namespace fc::crypto::blslib { static bls12_381::g1 parse_base58(const std::string& base58str) { - std::vector v1 = fc::from_base58(base58str); + const auto pivot = base58str.find('_'); + FC_ASSERT(pivot != std::string::npos, "No delimiter in string, cannot determine data type: ${str}", ("str", base58str)); - FC_ASSERT(v1.size() == 48); + const auto base_prefix_str = base58str.substr(0, 3); + FC_ASSERT(config::bls_public_key_base_prefix == base_prefix_str, "BLS Public Key has invalid base prefix: ${str}", ("str", base58str)("base_prefix_str", base_prefix_str)); + + const auto prefix_str = base58str.substr(pivot + 1, 3); + FC_ASSERT(config::bls_public_key_prefix == prefix_str, "BLS Public Key has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str)); + + auto data_str = base58str.substr(8); + + std::vector bytes = from_base58(data_str); + + FC_ASSERT(bytes.size() == 48); + std::array v2; - std::copy(v1.begin(), v1.end(), v2.begin()); + std::copy(bytes.begin(), bytes.end(), v2.begin()); std::optional g1 = bls12_381::g1::fromCompressedBytesBE(v2); FC_ASSERT(g1); return *g1; @@ -21,17 +33,15 @@ namespace fc { namespace crypto { namespace blslib { :_pkey(parse_base58(base58str)) {} - std::string bls_public_key::to_string(const fc::yield_function_t& yield)const { + std::string bls_public_key::to_string(const yield_function_t& yield)const { std::vector v2; std::array bytes = _pkey.toCompressedBytesBE(); std::copy(bytes.begin(), bytes.end(), std::back_inserter(v2)); - std::string data_str = fc::to_base58(v2, yield); + std::string data_str = to_base58(v2, yield); - //return std::string(config::bls_public_key_base_prefix) + "_" + data_str; - return data_str; - + return std::string(config::bls_public_key_base_prefix) + "_" + std::string(config::bls_public_key_prefix) + "_" + data_str; } @@ -40,18 +50,18 @@ namespace fc { namespace crypto { namespace blslib { return s; } -} } } // fc::crypto::blslib +} // fc::crypto::blslib namespace fc { using namespace std; - void to_variant(const fc::crypto::blslib::bls_public_key& var, fc::variant& vo, const fc::yield_function_t& yield) + void to_variant(const crypto::blslib::bls_public_key& var, variant& vo, const yield_function_t& yield) { vo = var.to_string(yield); } - void from_variant(const fc::variant& var, fc::crypto::blslib::bls_public_key& vo) + void from_variant(const variant& var, crypto::blslib::bls_public_key& vo) { - vo = fc::crypto::blslib::bls_public_key(var.as_string()); + vo = crypto::blslib::bls_public_key(var.as_string()); } } // fc diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 151728f115..53cc296a5b 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -2,17 +2,30 @@ #include #include -namespace fc { namespace crypto { namespace blslib { +namespace fc::crypto::blslib { static bls12_381::g2 sig_parse_base58(const std::string& base58str) { try { - std::vector v1 = fc::from_base58(base58str); + const auto pivot = base58str.find('_'); + FC_ASSERT(pivot != std::string::npos, "No delimiter in string, cannot determine data type: ${str}", ("str", base58str)); - FC_ASSERT(v1.size() == 96); + const auto base_prefix_str = base58str.substr(0, 3); + FC_ASSERT(config::bls_signature_base_prefix == base_prefix_str, "BLS Signature has invalid base prefix: ${str}", ("str", base58str)("base_prefix_str", base_prefix_str)); + + const auto prefix_str = base58str.substr(pivot + 1, 3); + FC_ASSERT(config::bls_signature_prefix == prefix_str, "BLS Signature has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str)); + + auto data_str = base58str.substr(8); + + std::vector bytes = from_base58(data_str); + + //std::vector v1 = from_base58(base58str); + + FC_ASSERT(bytes.size() == 96); std::array v2; - std::copy(v1.begin(), v1.end(), v2.begin()); + std::copy(bytes.begin(), bytes.end(), v2.begin()); std::optional g2 = bls12_381::g2::fromCompressedBytesBE(v2); FC_ASSERT(g2); return *g2; @@ -22,16 +35,16 @@ namespace fc { namespace crypto { namespace blslib { :_sig(sig_parse_base58(base58str)) {} - std::string bls_signature::to_string(const fc::yield_function_t& yield) const + std::string bls_signature::to_string(const yield_function_t& yield) const { std::vector v2; std::array bytes = _sig.toCompressedBytesBE(); std::copy(bytes.begin(), bytes.end(), std::back_inserter(v2)); - std::string data_str = fc::to_base58(v2, yield); + std::string data_str = to_base58(v2, yield); - return data_str; + return std::string(config::bls_signature_base_prefix) + "_" + std::string(config::bls_signature_prefix) + "_" + data_str; } @@ -44,17 +57,17 @@ namespace fc { namespace crypto { namespace blslib { return p1._sig == p2._sig; } -} } } // fc::crypto::blslib +} // fc::crypto::blslib namespace fc { - void to_variant(const fc::crypto::blslib::bls_signature& var, fc::variant& vo, const fc::yield_function_t& yield) + void to_variant(const crypto::blslib::bls_signature& var, variant& vo, const yield_function_t& yield) { vo = var.to_string(yield); } - void from_variant(const fc::variant& var, fc::crypto::blslib::bls_signature& vo) + void from_variant(const variant& var, crypto::blslib::bls_signature& vo) { - vo = fc::crypto::blslib::bls_signature(var.as_string()); + vo = crypto::blslib::bls_signature(var.as_string()); } } // fc diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index eabc553eb8..984044fac6 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_hotstuff_types) try { } FC_LOG_AND_RETHROW(); -//test serialization / deserialization of private key, public key and signature +//test serialization / deserialization of public key and signature BOOST_AUTO_TEST_CASE(bls_serialization_test) try { bls_private_key sk = bls_private_key(seed_1); @@ -249,6 +249,8 @@ BOOST_AUTO_TEST_CASE(bls_bad_sig_verif) try { //test private key base58 encoding BOOST_AUTO_TEST_CASE(bls_private_key_string_encoding) try { + //cout << "seed_1.size() : " << seed_1.size() << "\n"; + bls_private_key sk = bls_private_key(seed_1); bls_public_key pk = sk.get_public_key(); From a82c129c961aa18974adaf6e067f0ea9766052bd Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Wed, 23 Aug 2023 21:50:00 +0000 Subject: [PATCH 059/151] Renamed serialization tests in test_bls.cpp --- libraries/libfc/test/test_bls.cpp | 82 ++++++++----------------------- 1 file changed, 21 insertions(+), 61 deletions(-) diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 984044fac6..449bb0ee99 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -46,9 +46,6 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif) try { bls_signature signature = sk.sign(message_1); - //cout << "pk : " << pk.to_string() << "\n"; - //cout << "signature : " << signature.to_string() << "\n"; - // Verify the signature bool ok = verify(pk, message_1, signature); @@ -66,9 +63,6 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_digest) try { bls_signature signature = sk.sign(v); - //cout << "pk : " << pk.to_string() << "\n"; - //cout << "signature : " << signature.to_string() << "\n"; - // Verify the signature bool ok = verify(pk, v, signature); @@ -104,9 +98,6 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_hotstuff_types) try { agg_signature = aggregate({agg_signature, signature}); } - //cout << "pk : " << pk.to_string() << "\n"; - //cout << "signature : " << signature.to_string() << "\n"; - // Verify the signature bool ok = verify(agg_pk, v, agg_signature); @@ -114,31 +105,6 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_hotstuff_types) try { } FC_LOG_AND_RETHROW(); -//test serialization / deserialization of public key and signature -BOOST_AUTO_TEST_CASE(bls_serialization_test) try { - - bls_private_key sk = bls_private_key(seed_1); - bls_public_key pk = sk.get_public_key(); - - bls_signature signature = sk.sign(message_1); - - std::string pk_string = pk.to_string(); - std::string signature_string = signature.to_string(); - - //cout << pk_string << "\n"; - //cout << signature_string << "\n"; - - bls_public_key pk2 = bls_public_key(pk_string); - bls_signature signature2 = bls_signature(signature_string); - - //cout << pk2.to_string() << "\n"; - //cout << signature2.to_string() << "\n"; - - bool ok = verify(pk2, message_1, signature2); - - BOOST_CHECK_EQUAL(ok, true); - -} FC_LOG_AND_RETHROW(); //test public keys + signatures aggregation + verification BOOST_AUTO_TEST_CASE(bls_agg_sig_verif) try { @@ -148,23 +114,14 @@ BOOST_AUTO_TEST_CASE(bls_agg_sig_verif) try { bls_signature sig1 = sk1.sign(message_1); - //cout << "pk1 : " << pk1.to_string() << "\n"; - //cout << "sig1 : " << sig1.to_string() << "\n"; - bls_private_key sk2 = bls_private_key(seed_2); bls_public_key pk2 = sk2.get_public_key(); bls_signature sig2 = sk2.sign(message_1); - //cout << "pk2 : " << pk2.to_string() << "\n"; - //cout << "sig2 : " << sig2.to_string() << "\n"; - bls_public_key aggKey = aggregate({pk1, pk2}); bls_signature aggSig = aggregate({sig1, sig2}); - // cout << "aggKey : " << aggKey.to_string() << "\n"; - //cout << "aggSig : " << aggSig.to_string() << "\n"; - // Verify the signature bool ok = verify(aggKey, message_1, aggSig); @@ -181,21 +138,13 @@ BOOST_AUTO_TEST_CASE(bls_agg_tree_verif) try { bls_signature sig1 = sk1.sign(message_1); - //cout << "pk1 : " << pk1.to_string() << "\n"; - //cout << "sig1 : " << sig1.to_string() << "\n"; - bls_private_key sk2 = bls_private_key(seed_2); bls_public_key pk2 = sk2.get_public_key(); bls_signature sig2 = sk2.sign(message_2); - //cout << "pk2 : " << pk2.to_string() << "\n"; - //cout << "sig2 : " << sig2.to_string() << "\n"; - bls_signature aggSig = aggregate({sig1, sig2}); - //cout << "aggSig : " << aggSig.to_string() << "\n"; - vector pubkeys = {pk1, pk2}; vector> messages = {message_1, message_2}; @@ -246,10 +195,8 @@ BOOST_AUTO_TEST_CASE(bls_bad_sig_verif) try { } FC_LOG_AND_RETHROW(); -//test private key base58 encoding -BOOST_AUTO_TEST_CASE(bls_private_key_string_encoding) try { - - //cout << "seed_1.size() : " << seed_1.size() << "\n"; +//test bls private key base58 encoding / decoding / serialization / deserialization +BOOST_AUTO_TEST_CASE(bls_private_key_serialization) try { bls_private_key sk = bls_private_key(seed_1); @@ -257,16 +204,10 @@ BOOST_AUTO_TEST_CASE(bls_private_key_string_encoding) try { std::string priv_base58_str = sk.to_string(); - //cout << "priv_base58_str : " << priv_base58_str << "\n"; - bls_private_key sk2 = bls_private_key(priv_base58_str); - //cout << "sk2 : " << sk2.to_string() << "\n"; - bls_signature signature = sk2.sign(message_1); - //cout << "signature : " << signature.to_string() << "\n"; - // Verify the signature bool ok = verify(pk, message_1, signature); @@ -275,5 +216,24 @@ BOOST_AUTO_TEST_CASE(bls_private_key_string_encoding) try { } FC_LOG_AND_RETHROW(); +//test bls public key and bls signature base58 encoding / decoding / serialization / deserialization +BOOST_AUTO_TEST_CASE(bls_pub_key_sig_serialization) try { + + bls_private_key sk = bls_private_key(seed_1); + bls_public_key pk = sk.get_public_key(); + + bls_signature signature = sk.sign(message_1); + + std::string pk_string = pk.to_string(); + std::string signature_string = signature.to_string(); + + bls_public_key pk2 = bls_public_key(pk_string); + bls_signature signature2 = bls_signature(signature_string); + + bool ok = verify(pk2, message_1, signature2); + + BOOST_CHECK_EQUAL(ok, true); + +} FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_SUITE_END() From 8bcb4e70283f48a0ea29f41276685b394a32594f Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Wed, 23 Aug 2023 19:09:04 -0300 Subject: [PATCH 060/151] Avoid redundant state cache updates Co-authored-by: Gregory Popovitch --- libraries/hotstuff/chain_pacemaker.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 65729e5caa..ebb6248f72 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -124,11 +124,12 @@ namespace eosio { namespace hotstuff { csc prof("stat"); std::lock_guard g( _hotstuff_global_mutex ); // lock IF engine to read state prof.core_in(); - _qc_chain.get_state(current_state); current_state_version = _qc_chain.get_state_version(); // get potentially fresher version + if (_state_cache_version != current_state_version) + _qc_chain.get_state(current_state); prof.core_out(); } - { + if (_state_cache_version != current_state_version) { std::unique_lock ul(_state_cache_mutex); // lock cache for writing _state_cache = current_state; _state_cache_version = current_state_version; From 20e5cb02b17e6c5d7cf497830baa860f6f5ddeab Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 23 Aug 2023 18:10:53 -0400 Subject: [PATCH 061/151] Set up hotstuff_logger at initial time --- plugins/chain_plugin/chain_plugin.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 3381c48b11..a46b29352f 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -40,6 +40,9 @@ FC_REFLECT(chainbase::environment, (debug)(os)(arch)(boost_version)(compiler) ) const std::string deep_mind_logger_name("deep-mind"); eosio::chain::deep_mind_handler _deep_mind_log; +const std::string hotstuff_logger_name("hotstuff"); +fc::logger hotstuff_logger; + namespace eosio { //declare operator<< and validate function for read_mode in the same namespace as read_mode itself @@ -1194,6 +1197,7 @@ void chain_plugin::plugin_shutdown() { void chain_plugin::handle_sighup() { _deep_mind_log.update_logger( deep_mind_logger_name ); + fc::logger::update( hotstuff_logger_name, hotstuff_logger ); } chain_apis::read_write::read_write(controller& db, From 9062952a3a4b695884da904496f310e3ee71bfc4 Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Wed, 23 Aug 2023 21:07:58 -0300 Subject: [PATCH 062/151] Fix weak ++_state_version w/ make_scoped_exit Co-authored-by: Gregory Popovitch --- libraries/hotstuff/qc_chain.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 7d690b678e..84f0402c91 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -590,8 +590,9 @@ namespace eosio { namespace hotstuff { #ifdef QC_CHAIN_TRACE_DEBUG if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", msg.high_qc)("id", _id)); #endif - if (update_high_qc(msg.high_qc)) { - ++_state_version; // should be OK; update_high_qc() should not throw + auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); + if (!update_high_qc(msg.high_qc)) { + increment_version.cancel(); } } From abd0508438b84abd79555450964ced68b083a0d1 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 23 Aug 2023 21:33:50 -0400 Subject: [PATCH 063/151] Link all hotstuff components to FC logging --- libraries/hotstuff/chain_pacemaker.cpp | 5 ++-- .../eosio/hotstuff/chain_pacemaker.hpp | 4 ++- .../include/eosio/hotstuff/qc_chain.hpp | 4 ++- libraries/hotstuff/qc_chain.cpp | 5 ++-- libraries/hotstuff/test/test_hotstuff.cpp | 27 ++++++++----------- plugins/chain_plugin/chain_plugin.cpp | 4 +-- 6 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 7ca5bdd50b..ee22e0742d 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -100,9 +100,10 @@ namespace eosio { namespace hotstuff { #endif //=============================================================================================== - chain_pacemaker::chain_pacemaker(controller* chain, std::set my_producers, bool info_logging, bool error_logging) + chain_pacemaker::chain_pacemaker(controller* chain, std::set my_producers, const fc::logger& logger) : _chain(chain), - _qc_chain("default"_n, this, std::move(my_producers), info_logging, error_logging) + _qc_chain("default"_n, this, std::move(my_producers), logger), + _logger(logger) { } diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index 02e2aff59b..b781002cee 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -14,7 +14,7 @@ namespace eosio::hotstuff { //class-specific functions - chain_pacemaker(controller* chain, std::set my_producers, bool info_logging, bool error_logging); + chain_pacemaker(controller* chain, std::set my_producers, const fc::logger& logger); void beat(); @@ -61,6 +61,8 @@ namespace eosio::hotstuff { qc_chain _qc_chain; uint32_t _quorum_threshold = 15; //FIXME/TODO: calculate from schedule + const fc::logger& _logger; + }; } // namespace eosio::hotstuff diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 0a59c0dcb3..b8bf67339f 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -36,7 +36,7 @@ namespace eosio::hotstuff { qc_chain() = delete; - qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, bool info_logging, bool error_logging); + qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, const fc::logger& logger); #warning remove. bls12-381 key used for testing purposes //todo : remove. bls12-381 key used for testing purposes @@ -160,6 +160,8 @@ namespace eosio::hotstuff { // mutable std::mutex _state_mutex; + const fc::logger& _logger; + #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE // keep one proposal store (id -> proposal) by each height (height -> proposal store) typedef map proposal_store; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 22e5e6d1f2..a5f5b31cd2 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -310,12 +310,11 @@ namespace eosio { namespace hotstuff { } - qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, bool info_logging, bool error_logging) + qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, const fc::logger& logger) : _id(id), _pacemaker(pacemaker), _my_producers(std::move(my_producers)), - _log(info_logging), - _errors(error_logging) + _logger(logger) { if (_log) ilog(" === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); } diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 75c583c098..7607cb18f5 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -35,12 +35,14 @@ std::vector unique_replicas { "bpp"_n, "bpq"_n, "bpr"_n, "bps"_n, "bpt"_n, "bpu"_n }; +fc::logger hotstuff_logger; + class hotstuff_test_handler { public: std::vector>> _qc_chains; - void initialize_qc_chains(test_pacemaker& tpm, std::vector info_loggers, std::vector error_loggers, std::vector replicas){ + void initialize_qc_chains(test_pacemaker& tpm, std::vector replicas){ _qc_chains.clear(); @@ -51,14 +53,7 @@ class hotstuff_test_handler { //_qc_chains.reserve( replicas.size() ); for (name r : replicas) { - - bool log = std::find(info_loggers.begin(), info_loggers.end(), r) != info_loggers.end(); - bool err = std::find(error_loggers.begin(), error_loggers.end(), r) != error_loggers.end(); - - //If you want to force logging everything - //log = err = true; - - qc_chain *qcc_ptr = new qc_chain(r, &tpm, {r}, log, err); + qc_chain *qcc_ptr = new qc_chain(r, &tpm, {r}, hotstuff_logger); std::shared_ptr qcc_shared_ptr(qcc_ptr); _qc_chains.push_back( std::make_pair(r, qcc_shared_ptr) ); @@ -183,7 +178,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n}, unique_replicas); + ht.initialize_qc_chains(tpm, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); @@ -299,7 +294,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n}, {"bpa"_n}, unique_replicas); + ht.initialize_qc_chains(tpm, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); @@ -386,7 +381,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n},unique_replicas); + ht.initialize_qc_chains(tpm, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); @@ -502,7 +497,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n}, unique_replicas); + ht.initialize_qc_chains(tpm, unique_replicas); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); @@ -684,9 +679,9 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { hotstuff_test_handler ht1; hotstuff_test_handler ht2; - ht1.initialize_qc_chains(tpm1, {"bpe"_n}, {"bpe"_n}, replica_set_1); + ht1.initialize_qc_chains(tpm1, replica_set_1); - ht2.initialize_qc_chains(tpm2, {}, {}, replica_set_2); + ht2.initialize_qc_chains(tpm2, replica_set_2); tpm1.set_proposer("bpe"_n); //honest leader tpm1.set_leader("bpe"_n); @@ -831,7 +826,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, {"bpa"_n, "bpb"_n}, {"bpa"_n, "bpb"_n},unique_replicas); + ht.initialize_qc_chains(tpm, unique_replicas); tpm.set_proposer("bpg"_n); // can be any proposer that's not the leader for this test tpm.set_leader("bpa"_n); diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index a46b29352f..404803ea8b 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1116,9 +1116,7 @@ void chain_plugin_impl::plugin_initialize(const variables_map& options) { void chain_plugin::create_pacemaker(std::set my_producers) { EOS_ASSERT( !my->_chain_pacemaker, plugin_config_exception, "duplicate chain_pacemaker initialization" ); - const bool info_logging = true; - const bool error_logging = true; - my->_chain_pacemaker.emplace(&chain(), std::move(my_producers), info_logging, error_logging); + my->_chain_pacemaker.emplace(&chain(), std::move(my_producers), hotstuff_logger); } void chain_plugin::plugin_initialize(const variables_map& options) { From cb13c754ca98bf5dfc5ded05d604f1b9898be610 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 24 Aug 2023 10:41:54 -0400 Subject: [PATCH 064/151] use fc_ilog, fc_elog, fc_dlog, and fc_tlog instead of one ilog --- libraries/hotstuff/chain_pacemaker.cpp | 2 +- .../eosio/hotstuff/chain_pacemaker.hpp | 4 +- .../include/eosio/hotstuff/qc_chain.hpp | 4 +- libraries/hotstuff/qc_chain.cpp | 251 ++++++------------ 4 files changed, 85 insertions(+), 176 deletions(-) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index ee22e0742d..981a4bf818 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -100,7 +100,7 @@ namespace eosio { namespace hotstuff { #endif //=============================================================================================== - chain_pacemaker::chain_pacemaker(controller* chain, std::set my_producers, const fc::logger& logger) + chain_pacemaker::chain_pacemaker(controller* chain, std::set my_producers, fc::logger& logger) : _chain(chain), _qc_chain("default"_n, this, std::move(my_producers), logger), _logger(logger) diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index b781002cee..4a618d1320 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -14,7 +14,7 @@ namespace eosio::hotstuff { //class-specific functions - chain_pacemaker(controller* chain, std::set my_producers, const fc::logger& logger); + chain_pacemaker(controller* chain, std::set my_producers, fc::logger& logger); void beat(); @@ -61,7 +61,7 @@ namespace eosio::hotstuff { qc_chain _qc_chain; uint32_t _quorum_threshold = 15; //FIXME/TODO: calculate from schedule - const fc::logger& _logger; + fc::logger& _logger; }; diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index b8bf67339f..af0d12f9cc 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -36,7 +36,7 @@ namespace eosio::hotstuff { qc_chain() = delete; - qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, const fc::logger& logger); + qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, fc::logger& logger); #warning remove. bls12-381 key used for testing purposes //todo : remove. bls12-381 key used for testing purposes @@ -160,7 +160,7 @@ namespace eosio::hotstuff { // mutable std::mutex _state_mutex; - const fc::logger& _logger; + fc::logger& _logger; #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE // keep one proposal store (id -> proposal) by each height (height -> proposal store) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index a5f5b31cd2..37827db7a3 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -41,12 +41,6 @@ -- skip BPs without a bls key in the selection, new host functions are available */ - -// FIXME/REMOVE: remove all of this tracing -// Enables extra logging to help with debugging -//#define QC_CHAIN_TRACE_DEBUG - - namespace eosio { namespace hotstuff { const hs_proposal_message* qc_chain::get_proposal(const fc::sha256& proposal_id) { @@ -145,11 +139,9 @@ namespace eosio { namespace hotstuff { fc::unsigned_int qc_chain::update_bitset(fc::unsigned_int value, name finalizer ) { -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === update bitset ${value} ${finalizer}", + fc_tlog(_logger, " === update bitset ${value} ${finalizer}", ("value", value) ("finalizer", finalizer)); -#endif boost::dynamic_bitset b( 21, value ); vector finalizers = _pacemaker->get_finalizers(); @@ -157,19 +149,15 @@ namespace eosio { namespace hotstuff { if (finalizers[i] == finalizer) { b.flip(i); -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === finalizer found ${finalizer} new value : ${value}", + fc_tlog(_logger, " === finalizer found ${finalizer} new value : ${value}", ("finalizer", finalizer) ("value", b.to_ulong())); -#endif return b.to_ulong(); } } -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" *** finalizer not found ${finalizer}", + fc_tlog(_logger, " *** finalizer not found ${finalizer}", ("finalizer", finalizer)); -#endif throw std::runtime_error("qc_chain internal error: finalizer not found"); } @@ -217,7 +205,7 @@ namespace eosio { namespace hotstuff { if (p != nullptr) { b_new.final_on_qc = p->final_on_qc; } else { - if (_errors) ilog(" *** ${id} expected to find proposal in new_proposal_candidate() but not found : ${proposal_id}", ("id",_id)("proposal_id", b1.parent_id)); + fc_elog(_logger, " *** ${id} expected to find proposal in new_proposal_candidate() but not found : ${proposal_id}", ("id",_id)("proposal_id", b1.parent_id)); } } } @@ -225,8 +213,7 @@ namespace eosio { namespace hotstuff { b_new.proposal_id = get_digest_to_sign(b_new.block_id, b_new.phase_counter, b_new.final_on_qc); - if (_log) - ilog(" === ${id} creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", + fc_dlog(_logger, " === ${id} creating new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} : justify ${justify}", ("id", _id) ("block_num", b_new.block_num()) ("phase_counter", b_new.phase_counter) @@ -239,9 +226,7 @@ namespace eosio { namespace hotstuff { void qc_chain::reset_qc(const fc::sha256& proposal_id){ std::lock_guard g( _state_mutex ); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); _current_qc.proposal_id = proposal_id; _current_qc.quorum_met = false; _current_qc.active_finalizers = 0; @@ -300,9 +285,7 @@ namespace eosio { namespace hotstuff { return true; //skip evaluation if we've already verified quorum was met } else { -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === qc : ${qc}", ("qc", qc)); -#endif + fc_tlog(_logger, " === qc : ${qc}", ("qc", qc)); // If the caller wants to update the quorum_met flag on its "qc" object, it will have to do so // based on the return value of this method, since "qc" here is const. return evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); @@ -310,13 +293,13 @@ namespace eosio { namespace hotstuff { } - qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, const fc::logger& logger) + qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, fc::logger& logger) : _id(id), _pacemaker(pacemaker), _my_producers(std::move(my_producers)), _logger(logger) { - if (_log) ilog(" === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); + fc_dlog(_logger, " === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); } bool qc_chain::am_i_proposer(){ @@ -369,7 +352,7 @@ namespace eosio { namespace hotstuff { const hs_proposal_message *jp = get_proposal( proposal.justify.proposal_id ); if (jp == nullptr) { - if (_errors) ilog(" *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); + fc_elog(_logger, " *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); return; //can't recognize a proposal with an unknown justification } } @@ -377,11 +360,11 @@ namespace eosio { namespace hotstuff { const hs_proposal_message *p = get_proposal( proposal.proposal_id ); if (p != nullptr) { - if (_errors) ilog(" *** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); + fc_elog(_logger, " *** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); if (p->justify.proposal_id != proposal.justify.proposal_id) { - if (_errors) ilog(" *** ${id} two identical proposals (${proposal_id}) have different justifications : ${justify_1} vs ${justify_2}", + fc_elog(_logger, " *** ${id} two identical proposals (${proposal_id}) have different justifications : ${justify_1} vs ${justify_2}", ("id",_id) ("proposal_id", proposal.proposal_id) ("justify_1", p->justify.proposal_id) @@ -410,12 +393,12 @@ namespace eosio { namespace hotstuff { const hs_proposal_message & existing_proposal = *hgt_itr; #endif - if (_errors) ilog(" *** ${id} received a different proposal at the same height (${block_num}, ${phase_counter})", + fc_elog(_logger, " *** ${id} received a different proposal at the same height (${block_num}, ${phase_counter})", ("id",_id) ("block_num", existing_proposal.block_num()) ("phase_counter", existing_proposal.phase_counter)); - if (_errors) ilog(" *** Proposal #1 : ${proposal_id_1} Proposal #2 : ${proposal_id_2}", + fc_elog(_logger, " *** Proposal #1 : ${proposal_id_1} Proposal #2 : ${proposal_id_2}", ("proposal_id_1", existing_proposal.proposal_id) ("proposal_id_2", proposal.proposal_id)); @@ -428,7 +411,7 @@ namespace eosio { namespace hotstuff { } #endif - if (_log) ilog(" === ${id} received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", + fc_dlog(_logger, " === ${id} received new proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id} : parent_id ${parent_id} justify ${justify}", ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) @@ -461,13 +444,11 @@ namespace eosio { namespace hotstuff { hs_vote_message v_msg = sign_proposal(proposal, *prod_itr); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + fc_tlog(_logger, " === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) ("proposal_id", proposal.proposal_id)); -#endif //send_hs_vote_msg(v_msg); msgs.push_back(v_msg); @@ -478,13 +459,11 @@ namespace eosio { namespace hotstuff { } } -#ifdef QC_CHAIN_TRACE_DEBUG - else if (_log) ilog(" === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", + else fc_tlog(_logger, " === ${id} skipping signature on proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) ("proposal_id", proposal.proposal_id)); -#endif //update internal state update(proposal); @@ -497,7 +476,7 @@ namespace eosio { namespace hotstuff { leader_rotation_check(); //auto total_time = fc::time_point::now() - start; - //if (_log) ilog(" ... process_proposal() total time : ${total_time}", ("total_time", total_time)); + //fc_dlog(_logger, " ... process_proposal() total time : ${total_time}", ("total_time", total_time)); } void qc_chain::process_vote(const hs_vote_message & vote){ @@ -510,17 +489,14 @@ namespace eosio { namespace hotstuff { if (!am_leader) return; -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === Process vote from ${finalizer} : current bitset ${value}" , ("finalizer", vote.finalizer)("value", _current_qc.active_finalizers)); -#endif + fc_tlog(_logger, " === Process vote from ${finalizer} : current bitset ${value}" , ("finalizer", vote.finalizer)("value", _current_qc.active_finalizers)); // only leader need to take action on votes if (vote.proposal_id != _current_qc.proposal_id) return; const hs_proposal_message *p = get_proposal( vote.proposal_id ); if (p == nullptr) { - if (_errors) ilog(" *** ${id} couldn't find proposal", ("id",_id)); - if (_errors) ilog(" *** ${id} vote : ${vote}", ("vote", vote)("id",_id)); + fc_elog(_logger, " *** ${id} couldn't find proposal, vote : ${vote}", ("id",_id)("vote", vote)); return; } @@ -542,7 +518,7 @@ namespace eosio { namespace hotstuff { if (quorum_met){ - if (_log) ilog(" === ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", + fc_dlog(_logger, " === ${id} quorum met on #${block_num} ${phase_counter} ${proposal_id} ", ("block_num", p->block_num()) ("phase_counter", p->phase_counter) ("proposal_id", vote.proposal_id) @@ -552,7 +528,7 @@ namespace eosio { namespace hotstuff { _current_qc.quorum_met = true; state_lock.unlock(); - //ilog(" === update_high_qc : _current_qc ==="); + //fc_tlog(_logger, " === update_high_qc : _current_qc ==="); update_high_qc(_current_qc); //check for leader change @@ -560,9 +536,7 @@ namespace eosio { namespace hotstuff { //if we're operating in event-driven mode and the proposal hasn't reached the decide phase yet if (_chained_mode == false && p->phase_counter < 3) { -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); hs_proposal_message proposal_candidate; if (_pending_proposal_block == NULL_BLOCK_ID) @@ -571,30 +545,24 @@ namespace eosio { namespace hotstuff { proposal_candidate = new_proposal_candidate( _pending_proposal_block, 0 ); reset_qc(proposal_candidate.proposal_id); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); -#endif + fc_tlog(_logger, " === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); state_lock.lock(); _pending_proposal_block = NULL_BLOCK_ID; _b_leaf = proposal_candidate.proposal_id; state_lock.unlock(); send_hs_proposal_msg(proposal_candidate); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} _b_leaf updated (process_vote): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); } } } //auto total_time = fc::time_point::now() - start; - //if (_log) ilog(" ... process_vote() total time : ${total_time}", ("total_time", total_time)); + //fc_tlog(_logger, " ... process_vote() total time : ${total_time}", ("total_time", total_time)); } void qc_chain::process_new_view(const hs_new_view_message & msg){ -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} process_new_view === ${qc}", ("qc", msg.high_qc)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} process_new_view === ${qc}", ("qc", msg.high_qc)("id", _id)); update_high_qc(msg.high_qc); } @@ -604,16 +572,11 @@ namespace eosio { namespace hotstuff { #warning check for a need to gossip/rebroadcast even if it's not for us (maybe here, maybe somewhere else). // TODO: check for a need to gossip/rebroadcast even if it's not for us (maybe here, maybe somewhere else). if (! am_i_leader()) { - -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === ${id} process_new_block === discarding because I'm not the leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} process_new_block === discarding because I'm not the leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); return; } -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} process_new_block === am leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} process_new_block === am leader; block_id : ${bid}, justify : ${just}", ("bid", msg.block_id)("just", msg.justify)("id", _id)); #warning What to do with the received msg.justify? // ------------------------------------------------------------------ @@ -628,32 +591,26 @@ namespace eosio { namespace hotstuff { if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false) { -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", + fc_tlog(_logger, " === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", ("id", _id) ("proposal_id", _current_qc.proposal_id) ("quorum_met", _current_qc.quorum_met)); - if (_log) ilog(" === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", msg.block_id)); -#endif + fc_tlog(_logger, " === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", msg.block_id)); std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = msg.block_id; state_lock.unlock(); } else { -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", + fc_tlog(_logger, " === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", ("id", _id) ("proposal_id", _current_qc.proposal_id) ("quorum_met", _current_qc.quorum_met)); -#endif hs_proposal_message proposal_candidate = new_proposal_candidate( msg.block_id, 0 ); reset_qc(proposal_candidate.proposal_id); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} setting _pending_proposal_block to null (process_new_block)", ("id", _id)); -#endif + fc_tlog(_logger, " === ${id} setting _pending_proposal_block to null (process_new_block)", ("id", _id)); std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = NULL_BLOCK_ID; _b_leaf = proposal_candidate.proposal_id; @@ -661,39 +618,29 @@ namespace eosio { namespace hotstuff { send_hs_proposal_msg(proposal_candidate); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} _b_leaf updated (on_beat): ${proposal_id}", ("proposal_id", proposal_candidate.proposal_id)("id", _id)); } } void qc_chain::send_hs_proposal_msg(const hs_proposal_message & msg){ -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === broadcast_hs_proposal ==="); -#endif + fc_tlog(_logger, " === broadcast_hs_proposal ==="); _pacemaker->send_hs_proposal_msg(msg, _id); process_proposal(msg); } void qc_chain::send_hs_vote_msg(const hs_vote_message & msg){ -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === broadcast_hs_vote ==="); -#endif + fc_tlog(_logger, " === broadcast_hs_vote ==="); _pacemaker->send_hs_vote_msg(msg, _id); process_vote(msg); } void qc_chain::send_hs_new_view_msg(const hs_new_view_message & msg){ -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === broadcast_hs_new_view ==="); -#endif + fc_tlog(_logger, " === broadcast_hs_new_view ==="); _pacemaker->send_hs_new_view_msg(msg, _id); } void qc_chain::send_hs_new_block_msg(const hs_new_block_message & msg){ -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === broadcast_hs_new_block ==="); -#endif + fc_tlog(_logger, " === broadcast_hs_new_block ==="); _pacemaker->send_hs_new_block_msg(msg, _id); } @@ -709,19 +656,19 @@ namespace eosio { namespace hotstuff { fc::sha256 parent_id = p->parent_id; p = get_proposal( parent_id ); if (p == nullptr) { - if (_errors) ilog(" *** ${id} cannot find proposal id while looking for ancestor : ${proposal_id}", ("id",_id)("proposal_id", parent_id)); + fc_elog(_logger, " *** ${id} cannot find proposal id while looking for ancestor : ${proposal_id}", ("id",_id)("proposal_id", parent_id)); return false; } if (p->proposal_id == ancestor) { if (counter > 25) { - if (_errors) ilog(" *** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); + fc_elog(_logger, " *** ${id} took ${counter} iterations to find ancestor ", ("id",_id)("counter", counter)); } return true; } ++counter; } - if (_errors) ilog(" *** ${id} extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", + fc_elog(_logger, " *** ${id} extends returned false : could not find ${d_proposal_id} descending from ${a_proposal_id} ", ("id",_id) ("d_proposal_id", descendant) ("a_proposal_id", ancestor)); @@ -754,9 +701,7 @@ namespace eosio { namespace hotstuff { // I am the proposer; so this assumes that no additional proposal validation is required. -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === I am a leader-proposer that is proposing a block for itself to lead"); -#endif + fc_tlog(_logger, " === I am a leader-proposer that is proposing a block for itself to lead"); // Hardwired consumption by self; no networking. process_new_block( block_candidate ); @@ -765,18 +710,14 @@ namespace eosio { namespace hotstuff { // I'm only a proposer and not the leader; send a new-block-proposal message out to // the network, until it reaches the leader. -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === broadcasting new block = #${block_height} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_height",compute_block_num(block_candidate.block_id) )); -#endif + fc_tlog(_logger, " === broadcasting new block = #${block_num} ${proposal_id}", ("proposal_id", block_candidate.block_id)("block_num",(block_header::num_from_id(block_candidate.block_id)))); send_hs_new_block_msg( block_candidate ); } } void qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); -#endif + fc_tlog(_logger, " === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); // if new high QC is higher than current, update to new @@ -787,9 +728,7 @@ namespace eosio { namespace hotstuff { _b_leaf = _high_qc.proposal_id; state_lock.unlock(); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } else { const hs_proposal_message *old_high_qc_prop = get_proposal( _high_qc.proposal_id ); const hs_proposal_message *new_high_qc_prop = get_proposal( high_qc.proposal_id ); @@ -804,18 +743,14 @@ namespace eosio { namespace hotstuff { // "The caller does not need this updated on their high_qc structure" -- g //high_qc.quorum_met = true; -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); -#endif + fc_tlog(_logger, " === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); std::unique_lock state_lock( _state_mutex ); _high_qc = high_qc; _high_qc.quorum_met = true; _b_leaf = _high_qc.proposal_id; state_lock.unlock(); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); } } } @@ -829,7 +764,7 @@ namespace eosio { namespace hotstuff { if (current_leader != next_leader){ - if (_log) ilog(" /// ${id} rotating leader : ${old_leader} -> ${new_leader} ", + fc_dlog(_logger, " /// ${id} rotating leader : ${old_leader} -> ${new_leader} ", ("id", _id) ("old_leader", current_leader) ("new_leader", next_leader)); @@ -838,9 +773,7 @@ namespace eosio { namespace hotstuff { reset_qc(NULL_PROPOSAL_ID); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); -#endif + fc_tlog(_logger, " === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); std::unique_lock state_lock( _state_mutex ); _pending_proposal_block = NULL_BLOCK_ID; @@ -857,7 +790,7 @@ namespace eosio { namespace hotstuff { //safenode predicate bool qc_chain::is_node_safe(const hs_proposal_message & proposal){ - //ilog(" === is_node_safe ==="); + //fc_tlog(_logger, " === is_node_safe ==="); bool monotony_check = false; bool safety_check = false; @@ -890,7 +823,7 @@ namespace eosio { namespace hotstuff { if (p != nullptr) { upcoming_commit = p->final_on_qc; } else { - if (_errors) ilog(" *** ${id} in is_node_safe did not find expected proposal id: ${proposal_id}", ("id",_id)("proposal_id", b1.parent_id)); + fc_elog(_logger, " *** ${id} in is_node_safe did not find expected proposal id: ${proposal_id}", ("id",_id)("proposal_id", b1.parent_id)); } } } @@ -930,24 +863,19 @@ namespace eosio { namespace hotstuff { liveness_check = true; safety_check = true; -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} not locked on anything, liveness and safety are true", ("id", _id)); -#endif + fc_tlog(_logger, " === ${id} not locked on anything, liveness and safety are true", ("id", _id)); } -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", + fc_tlog(_logger, " === final_on_qc_check : ${final_on_qc_check}, monotony_check : ${monotony_check}, liveness_check : ${liveness_check}, safety_check : ${safety_check}", ("final_on_qc_check", final_on_qc_check) ("monotony_check", monotony_check) ("liveness_check", liveness_check) ("safety_check", safety_check)); -#endif bool node_is_safe = final_on_qc_check && monotony_check && (liveness_check || safety_check); if (!node_is_safe) { - if (_errors) - ilog(" *** node is NOT safe. Checks : final_on_qc: ${final_on_qc}, monotony_check: ${monotony_check}, liveness_check: ${liveness_check}, safety_check: ${safety_check})", + fc_elog(_logger, " *** node is NOT safe. Checks : final_on_qc: ${final_on_qc}, monotony_check: ${monotony_check}, liveness_check: ${liveness_check}, safety_check: ${safety_check})", ("final_on_qc_check",final_on_qc_check) ("monotony_check",monotony_check) ("liveness_check",liveness_check) @@ -979,10 +907,10 @@ namespace eosio { namespace hotstuff { } void qc_chain::update(const hs_proposal_message & proposal){ - //ilog(" === update internal state ==="); + //fc_tlog(_logger, " === update internal state ==="); //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ - if (_log) ilog(" === ${id} proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)("id", _id)); + fc_dlog(_logger, " === ${id} proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)("id", _id)); return; } @@ -993,11 +921,11 @@ namespace eosio { namespace hotstuff { const hs_proposal_message *b_lock = get_proposal( _b_lock ); EOS_ASSERT( b_lock != nullptr || _b_lock == NULL_PROPOSAL_ID , chain_exception, "expected hs_proposal ${id} not found", ("id", _b_lock) ); - //ilog(" === update_high_qc : proposal.justify ==="); + //fc_tlog(_logger, " === update_high_qc : proposal.justify ==="); update_high_qc(proposal.justify); if (chain_length<1){ - if (_log) ilog(" === ${id} qc chain length is 0", ("id", _id)); + fc_dlog(_logger, " === ${id} qc chain length is 0", ("id", _id)); return; } @@ -1005,7 +933,7 @@ namespace eosio { namespace hotstuff { hs_proposal_message b_2 = *itr; if (chain_length<2){ - if (_log) ilog(" === ${id} qc chain length is 1", ("id", _id)); + fc_dlog(_logger, " === ${id} qc chain length is 1", ("id", _id)); return; } @@ -1015,35 +943,29 @@ namespace eosio { namespace hotstuff { //if we're not locked on anything, means we just activated or chain just launched, else we verify if we've progressed enough to establish a new lock -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height}", + fc_tlog(_logger, " === ${id} _b_lock ${_b_lock} b_1 height ${b_1_height}", ("id", _id) ("_b_lock", _b_lock) ("b_1_height", b_1.block_num()) ("b_1_phase", b_1.phase_counter)); if ( b_lock != nullptr ) { - if (_log) ilog(" === b_lock height ${b_lock_height} b_lock phase ${b_lock_phase}", + fc_tlog(_logger, " === b_lock height ${b_lock_height} b_lock phase ${b_lock_phase}", ("b_lock_height", b_lock->block_num()) ("b_lock_phase", b_lock->phase_counter)); } -#endif if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ -#ifdef QC_CHAIN_TRACE_DEBUG - ilog("setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); -#endif + fc_tlog(_logger, "setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); std::unique_lock state_lock( _state_mutex ); _b_lock = b_1.proposal_id; //commit phase on b1 state_lock.unlock(); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); -#endif + fc_tlog(_logger, " === ${id} _b_lock updated : ${proposal_id}", ("proposal_id", b_1.proposal_id)("id", _id)); } if (chain_length < 3) { - if (_log) ilog(" === ${id} qc chain length is 2",("id", _id)); + fc_dlog(_logger, " === ${id} qc chain length is 2",("id", _id)); return; } @@ -1051,13 +973,11 @@ namespace eosio { namespace hotstuff { hs_proposal_message b = *itr; -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", + fc_tlog(_logger, " === direct parent relationship verification : b_2.parent_id ${b_2.parent_id} b_1.proposal_id ${b_1.proposal_id} b_1.parent_id ${b_1.parent_id} b.proposal_id ${b.proposal_id} ", ("b_2.parent_id",b_2.parent_id) ("b_1.proposal_id", b_1.proposal_id) ("b_1.parent_id", b_1.parent_id) ("b.proposal_id", b.proposal_id)); -#endif //direct parent relationship verification if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ @@ -1069,8 +989,7 @@ namespace eosio { namespace hotstuff { if (b_exec->get_height() >= b.get_height() && b_exec->proposal_id != b.proposal_id){ - if (_errors) - ilog(" *** ${id} finality violation detected at height ${block_num}, phase : ${phase}. Proposal ${proposal_id_1} conflicts with ${proposal_id_2}", + fc_elog(_logger, " *** ${id} finality violation detected at height ${block_num}, phase : ${phase}. Proposal ${proposal_id_1} conflicts with ${proposal_id_2}", ("id", _id) ("block_num", b.block_num()) ("phase", b.phase_counter) @@ -1088,9 +1007,7 @@ namespace eosio { namespace hotstuff { commit(b); -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); -#endif + fc_tlog(_logger, " === last executed proposal : #${block_num} ${block_id}", ("block_num", b.block_num())("block_id", b.block_id)); std::unique_lock state_lock( _state_mutex ); _b_exec = b.proposal_id; //decide phase on b @@ -1100,15 +1017,15 @@ namespace eosio { namespace hotstuff { gc_proposals( b.get_height()-1); } else { - if (_errors) ilog(" *** ${id} could not verify direct parent relationship", ("id",_id)); - if (_errors) ilog(" *** b_2 ${b_2}", ("b_2", b_2)); - if (_errors) ilog(" *** b_1 ${b_1}", ("b_1", b_1)); - if (_errors) ilog(" *** b ${b}", ("b", b)); + fc_elog(_logger, " *** ${id} could not verify direct parent relationship", ("id",_id)); + fc_elog(_logger, " *** b_2 ${b_2}", ("b_2", b_2)); + fc_elog(_logger, " *** b_1 ${b_1}", ("b_1", b_1)); + fc_elog(_logger, " *** b ${b}", ("b", b)); } } void qc_chain::gc_proposals(uint64_t cutoff){ - //ilog(" === garbage collection on old data"); + //fc_tlog(_logger, " === garbage collection on old data"); std::lock_guard g( _state_mutex ); #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE ps_height_iterator psh_it = _proposal_stores_by_height.begin(); @@ -1137,14 +1054,12 @@ namespace eosio { namespace hotstuff { auto end_itr = _proposal_store.get().upper_bound(cutoff); while (_proposal_store.get().begin() != end_itr){ auto itr = _proposal_store.get().begin(); -#ifdef QC_CHAIN_TRACE_DEBUG - if (_log) ilog(" === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", + fc_tlog(_logger, " === ${id} erasing ${block_num} ${phase_counter} ${block_id} proposal_id ${proposal_id}", ("id", _id) ("block_num", itr->block_num()) ("phase_counter", itr->phase_counter) ("block_id", itr->block_id) ("proposal_id", itr->proposal_id)); -#endif _proposal_store.get().erase(itr); } #endif @@ -1152,40 +1067,36 @@ namespace eosio { namespace hotstuff { void qc_chain::commit(const hs_proposal_message & proposal){ -#ifdef QC_CHAIN_TRACE_DEBUG - ilog(" === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + fc_tlog(_logger, " === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", ("block_num", proposal.block_num()) ("proposal_id", proposal.proposal_id) ("block_id", proposal.block_id) ("phase_counter", proposal.phase_counter) ("parent_id", proposal.parent_id)); -#endif bool exec_height_check = false; const hs_proposal_message *last_exec_prop = get_proposal( _b_exec ); EOS_ASSERT( last_exec_prop != nullptr || _b_exec == NULL_PROPOSAL_ID, chain_exception, "expected hs_proposal ${id} not found", ("id", _b_exec) ); -#ifdef QC_CHAIN_TRACE_DEBUG if (last_exec_prop != nullptr) { - ilog(" === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", + fc_tlog(_logger, " === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", ("block_num", last_exec_prop->block_num()) ("proposal_id", last_exec_prop->proposal_id) ("block_id", last_exec_prop->block_id) ("phase_counter", last_exec_prop->phase_counter) ("parent_id", last_exec_prop->parent_id)); - ilog(" *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", + fc_tlog(_logger, " *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", ("proposal_id_1", last_exec_prop->block_num()) ("phase_counter_1", last_exec_prop->phase_counter) ("proposal_id_2", proposal.block_num()) ("phase_counter_2", proposal.phase_counter)); } else { - ilog(" === _b_exec proposal is null vs proposal ${proposal_id_2} ${phase_counter_2} ", + fc_tlog(_logger, " === _b_exec proposal is null vs proposal ${proposal_id_2} ${phase_counter_2} ", ("proposal_id_2", proposal.block_num()) ("phase_counter_2", proposal.phase_counter)); } -#endif if (_b_exec == NULL_PROPOSAL_ID) exec_height_check = true; @@ -1196,13 +1107,13 @@ namespace eosio { namespace hotstuff { const hs_proposal_message *p = get_proposal( proposal.parent_id ); if (p != nullptr) { - //ilog(" === recursively committing" ); + //fc_tlog(_logger, " === recursively committing" ); commit(*p); //recursively commit all non-committed ancestor blocks sequentially first } //Execute commands [...] - if (_log) ilog(" === ${id} committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", + fc_dlog(_logger, " === ${id} committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) @@ -1210,13 +1121,11 @@ namespace eosio { namespace hotstuff { ("proposal_id", proposal.proposal_id)); } else { -#ifdef QC_CHAIN_TRACE_DEBUG - if (_errors) ilog(" *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", + fc_elog(_logger, " *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", ("id", _id) ("block_num", proposal.block_num()) ("phase_counter", proposal.phase_counter) ("proposal_id", proposal.proposal_id)); -#endif } } From 4918c7b5e5add389d8c24ab8a84d72c4bf13327f Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 24 Aug 2023 10:44:01 -0400 Subject: [PATCH 065/151] update logging.json --- programs/nodeos/logging.json | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/programs/nodeos/logging.json b/programs/nodeos/logging.json index 887d2ae13d..95de98eb68 100644 --- a/programs/nodeos/logging.json +++ b/programs/nodeos/logging.json @@ -154,6 +154,15 @@ "level": "info", "enabled": true, "additivity": false, + "appenders": [ + "stderr", + "net" + ] + },{ + "name": "hotstuff", + "level": "debug", + "enabled": true, + "additivity": false, "appenders": [ "stderr", "net" From 5d81bdd167f79b9f2338fb9bf84170e1e1d67e0e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 25 Aug 2023 07:35:42 -0500 Subject: [PATCH 066/151] GH-1519 Rm unused file --- .../eosio/producer_plugin/qc_chain.hpp.bkp | 70 ------------------- 1 file changed, 70 deletions(-) delete mode 100644 plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp.bkp diff --git a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp.bkp b/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp.bkp deleted file mode 100644 index 8b177295cf..0000000000 --- a/plugins/producer_plugin/include/eosio/producer_plugin/qc_chain.hpp.bkp +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once -#include -#include -#include - -namespace eosio { namespace chain { - - const uint32_t INTERUPT_TIMEOUT = 6; //sufficient timeout for new leader to be selected - - class qc_chain { - public: - - qc_chain( ){}; - ~qc_chain(){}; - - name get_proposer(); - name get_leader(); - name get_incoming_leader(); - - bool is_quorum_met(eosio::chain::quorum_certificate qc, extended_schedule schedule, hs_proposal_message proposal); - - std::vector get_finalizers(); - - hs_proposal_message new_proposal_candidate(block_id_type block_id, uint8_t phase_counter); - hs_new_block_message new_block_candidate(block_id_type block_id); - - void init(chain_plugin& chain_plug, std::set my_producers); - - block_header_state_ptr get_block_header( const block_id_type& id ); - - bool am_i_proposer(); - bool am_i_leader(); - bool am_i_finalizer(); - - void process_proposal(hs_proposal_message msg); - void process_vote(hs_vote_message msg); - void process_new_view(hs_new_view_message msg); - void process_new_block(hs_new_block_message msg); - - void broadcast_hs_proposal(hs_proposal_message msg); - void broadcast_hs_vote(hs_vote_message msg); - void broadcast_hs_new_view(hs_new_view_message msg); - void broadcast_hs_new_block(hs_new_block_message msg); - - bool extends(fc::sha256 descendant, fc::sha256 ancestor); - - void on_beat(block_state& hbs); - - void update_high_qc(eosio::chain::quorum_certificate high_qc); - - void on_leader_rotate(); - - bool is_node_safe(hs_proposal_message proposal); - - std::vector get_qc_chain(fc::sha256 proposal_id); - - void on_hs_vote_msg(hs_vote_message msg); //confirmation msg event handler - void on_hs_proposal_msg(hs_proposal_message msg); //consensus msg event handler - void on_hs_new_view_msg(hs_new_view_message msg); //new view msg event handler - void on_hs_new_block_msg(hs_new_block_message msg); //new block msg event handler - - void update(hs_proposal_message proposal); - void commit(hs_proposal_message proposal); - - void clear_old_data(uint64_t cutoff); - - std::mutex _hotstuff_state_mutex; - - }; -}} /// eosio::qc_chain \ No newline at end of file From 32e9243c7647a900284cb0a5a3192f8c96a820b8 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 25 Aug 2023 09:24:37 -0500 Subject: [PATCH 067/151] GH-1519 Remove hotstuff emit messages in controller. Simplify and optimize hotstuff message sending in net_plugin. --- libraries/chain/controller.cpp | 32 ---- .../chain/include/eosio/chain/controller.hpp | 29 ---- libraries/hotstuff/chain_pacemaker.cpp | 33 +++- .../eosio/hotstuff/chain_pacemaker.hpp | 10 ++ plugins/chain_plugin/chain_plugin.cpp | 25 ++- .../eosio/chain_plugin/chain_plugin.hpp | 8 +- .../include/eosio/net_plugin/net_plugin.hpp | 3 +- plugins/net_plugin/net_plugin.cpp | 153 +++++++----------- 8 files changed, 125 insertions(+), 168 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 037dc6de50..bad536b07a 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1974,22 +1974,6 @@ struct controller_impl { pending->push(); } - void commit_hs_proposal_msg(hs_proposal_message_ptr msg){ - emit( self.new_hs_proposal_message, msg ); - } - - void commit_hs_vote_msg(hs_vote_message_ptr msg){ - emit( self.new_hs_vote_message, msg ); - } - - void commit_hs_new_view_msg(hs_new_view_message_ptr msg){ - emit( self.new_hs_new_view_message, msg ); - } - - void commit_hs_new_block_msg(hs_new_block_message_ptr msg){ - emit( self.new_hs_new_block_message, msg ); - } - /** * 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 @@ -2983,22 +2967,6 @@ void controller::commit_block() { my->commit_block(block_status::incomplete); } -void controller::commit_hs_proposal_msg(hs_proposal_message_ptr msg) { - my->commit_hs_proposal_msg(msg); -} - -void controller::commit_hs_vote_msg(hs_vote_message_ptr msg) { - my->commit_hs_vote_msg(msg); -} - -void controller::commit_hs_new_view_msg(hs_new_view_message_ptr msg) { - my->commit_hs_new_view_msg(msg); -} - -void controller::commit_hs_new_block_msg(hs_new_block_message_ptr msg) { - my->commit_hs_new_block_msg(msg); -} - deque controller::abort_block() { return my->abort_block(); } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 934ed25dac..5f0da59768 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -21,15 +21,6 @@ namespace eosio { namespace vm { class wasm_allocator; }} namespace eosio { namespace chain { - struct hs_proposal_message; - struct hs_vote_message; - struct hs_new_view_message; - struct hs_new_block_message; - using hs_proposal_message_ptr = std::shared_ptr; - using hs_vote_message_ptr = std::shared_ptr; - using hs_new_view_message_ptr = std::shared_ptr; - using hs_new_block_message_ptr = std::shared_ptr; - class authorization_manager; namespace resource_limits { @@ -176,12 +167,6 @@ namespace eosio { namespace chain { void sign_block( const signer_callback_type& signer_callback ); void commit_block(); - void commit_hs_proposal_msg(hs_proposal_message_ptr msg); - void commit_hs_vote_msg(hs_vote_message_ptr msg); - - void commit_hs_new_view_msg(hs_new_view_message_ptr msg); - void commit_hs_new_block_msg(hs_new_block_message_ptr msg); - // thread-safe std::future create_block_state_future( const block_id_type& id, const signed_block_ptr& b ); // thread-safe @@ -352,20 +337,6 @@ namespace eosio { namespace chain { signal accepted_transaction; signal)> applied_transaction; signal bad_alloc; - signal new_hs_proposal_message; - signal new_hs_vote_message; - signal new_hs_new_view_message; - signal new_hs_new_block_message; - - /* - signal pre_apply_block; - signal post_apply_block; - signal abort_apply_block; - signal pre_apply_transaction; - signal post_apply_transaction; - signal pre_apply_action; - signal post_apply_action; - */ const apply_handler* find_apply_handler( account_name contract, scope_name scope, action_name act )const; wasm_interface_collection& get_wasm_interface(); diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index f5763150e9..e4d4c238e4 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -107,6 +107,23 @@ namespace eosio { namespace hotstuff { { } + void chain_pacemaker::register_bcast_functions( + std::function on_proposal_message, + std::function on_vote_message, + std::function on_new_block_message, + std::function on_new_view_message + ) { + FC_ASSERT(on_proposal_message, "on_proposal_message must be provided"); + FC_ASSERT(on_vote_message, "on_proposal_message must be provided"); + FC_ASSERT(on_new_block_message, "on_proposal_message must be provided"); + FC_ASSERT(on_new_view_message, "on_proposal_message must be provided"); + std::lock_guard g( _hotstuff_global_mutex ); // not actually needed but doesn't hurt + bcast_proposal_message = std::move(on_proposal_message); + bcast_vote_message = std::move(on_vote_message); + bcast_new_block_message = std::move(on_new_block_message); + bcast_new_view_message = std::move(on_new_view_message); + } + // Called internally by the chain_pacemaker to decide whether it should do something or not, based on feature activation. // Only methods called by the outside need to call this; methods called by qc_chain only don't need to check for enable(). bool chain_pacemaker::enabled() const { @@ -265,25 +282,22 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, name id) { - hs_proposal_message_ptr msg_ptr = std::make_shared(msg); - _chain->commit_hs_proposal_msg(msg_ptr); + bcast_proposal_message(msg); } void chain_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, name id) { - hs_vote_message_ptr msg_ptr = std::make_shared(msg); - _chain->commit_hs_vote_msg(msg_ptr); + bcast_vote_message(msg); } void chain_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, name id) { - hs_new_block_message_ptr msg_ptr = std::make_shared(msg); - _chain->commit_hs_new_block_msg(msg_ptr); + bcast_new_block_message(msg); } void chain_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, name id) { - hs_new_view_message_ptr msg_ptr = std::make_shared(msg); - _chain->commit_hs_new_view_msg(msg_ptr); + bcast_new_view_message(msg); } + // called from net threads void chain_pacemaker::on_hs_proposal_msg(const hs_proposal_message& msg) { if (! enabled()) return; @@ -295,6 +309,7 @@ namespace eosio { namespace hotstuff { prof.core_out(); } + // called from net threads void chain_pacemaker::on_hs_vote_msg(const hs_vote_message& msg) { if (! enabled()) return; @@ -306,6 +321,7 @@ namespace eosio { namespace hotstuff { prof.core_out(); } + // called from net threads void chain_pacemaker::on_hs_new_block_msg(const hs_new_block_message& msg) { if (! enabled()) return; @@ -317,6 +333,7 @@ namespace eosio { namespace hotstuff { prof.core_out(); } + // called from net threads void chain_pacemaker::on_hs_new_view_msg(const hs_new_view_message& msg) { if (! enabled()) return; diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index b61015d0a6..8730a1b206 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -17,6 +17,12 @@ namespace eosio::hotstuff { //class-specific functions chain_pacemaker(controller* chain, std::set my_producers, fc::logger& logger); + void register_bcast_functions( + std::function on_proposal_message, + std::function on_vote_message, + std::function on_new_block_message, + std::function on_new_view_message + ); void beat(); @@ -67,6 +73,10 @@ namespace eosio::hotstuff { chain::controller* _chain = nullptr; qc_chain _qc_chain; + std::function bcast_proposal_message; + std::function bcast_vote_message; + std::function bcast_new_block_message; + std::function bcast_new_view_message; uint32_t _quorum_threshold = 15; //FIXME/TODO: calculate from schedule fc::logger& _logger; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 404803ea8b..010408dd84 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1119,6 +1119,20 @@ void chain_plugin::create_pacemaker(std::set my_producers) my->_chain_pacemaker.emplace(&chain(), std::move(my_producers), hotstuff_logger); } +void chain_plugin::register_pacemaker_bcast_functions( + std::function on_proposal_message, + std::function on_vote_message, + std::function on_new_block_message, + std::function on_new_view_message) { + EOS_ASSERT( my->_chain_pacemaker, plugin_config_exception, "chain_pacemaker not created" ); + my->_chain_pacemaker->register_bcast_functions( + std::move(on_proposal_message), + std::move(on_vote_message), + std::move(on_new_block_message), + std::move(on_new_view_message)); +} + + void chain_plugin::plugin_initialize(const variables_map& options) { handle_sighup(); // Sets loggers my->plugin_initialize(options); @@ -2651,7 +2665,7 @@ read_only::get_finalizer_state_results read_only::get_finalizer_state(const get_finalizer_state_params&, const fc::time_point& deadline ) const { get_finalizer_state_results results; - if ( chain_pacemaker ) { // producer_plug is null when called from chain_plugin_tests.cpp and get_table_tests.cpp + if ( chain_pacemaker ) { // is null when called from chain_plugin_tests.cpp and get_table_tests.cpp finalizer_state fs; chain_pacemaker->get_state( fs ); results.chained_mode = fs.chained_mode; @@ -2665,8 +2679,9 @@ read_only::get_finalizer_state(const get_finalizer_state_params&, const fc::time results.high_qc = fs.high_qc; results.current_qc = fs.current_qc; results.schedule = fs.schedule; - for (auto proposal: fs.proposals) { - chain::hs_proposal_message & p = proposal.second; + results.proposals.reserve( fs.proposals.size() ); + for (const auto& proposal : fs.proposals) { + const chain::hs_proposal_message& p = proposal.second; results.proposals.push_back( hs_complete_proposal_message( p ) ); } } @@ -2675,18 +2690,22 @@ read_only::get_finalizer_state(const get_finalizer_state_params&, const fc::time } // namespace chain_apis +// called from net threads void chain_plugin::notify_hs_vote_message( const hs_vote_message& msg ) { my->_chain_pacemaker->on_hs_vote_msg(msg); }; +// called from net threads void chain_plugin::notify_hs_proposal_message( const hs_proposal_message& msg ) { my->_chain_pacemaker->on_hs_proposal_msg(msg); }; +// called from net threads void chain_plugin::notify_hs_new_view_message( const hs_new_view_message& msg ) { my->_chain_pacemaker->on_hs_new_view_msg(msg); }; +// called from net threads void chain_plugin::notify_hs_new_block_message( const hs_new_block_message& msg ) { my->_chain_pacemaker->on_hs_new_block_msg(msg); }; diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index c9a9feb6dd..1e3bffb831 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -843,7 +843,7 @@ class read_only : public api_base { uint8_t phase_counter = 0; uint32_t block_height = 0; uint64_t view_number = 0; - explicit hs_complete_proposal_message( const chain::hs_proposal_message & p ) { + explicit hs_complete_proposal_message( const chain::hs_proposal_message& p ) { proposal_id = p.proposal_id; block_id = p.block_id; parent_id = p.parent_id; @@ -1032,6 +1032,12 @@ class chain_plugin : public plugin { const controller& chain() const; void create_pacemaker(std::set my_producers); + void register_pacemaker_bcast_functions( + std::function on_proposal_message, + std::function on_vote_message, + std::function on_new_block_message, + std::function on_new_view_message + ); void notify_hs_vote_message( const chain::hs_vote_message& msg ); void notify_hs_proposal_message( const chain::hs_proposal_message& msg ); void notify_hs_new_view_message( const chain::hs_new_view_message& msg ); diff --git a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp index d0c482e5b1..c18fb4e12c 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/net_plugin.hpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace eosio { using namespace appbase; @@ -26,7 +27,7 @@ namespace eosio { net_plugin(); virtual ~net_plugin(); - APPBASE_PLUGIN_REQUIRES((chain_plugin)) + APPBASE_PLUGIN_REQUIRES((chain_plugin)(producer_plugin)) virtual void set_program_options(options_description& cli, options_description& cfg) override; void handle_sighup() override; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 42167d89a9..68621f32e2 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -78,6 +78,7 @@ namespace eosio { using connection_ptr = std::shared_ptr; using connection_wptr = std::weak_ptr; + using send_buffer_type = std::shared_ptr>; static constexpr int64_t block_interval_ns = std::chrono::duration_cast(std::chrono::milliseconds(config::block_interval_ms)).count(); @@ -300,10 +301,7 @@ namespace eosio { bool have_txn( const transaction_id_type& tid ) const; void expire_txns(); - void bcast_hs_proposal_msg(const hs_proposal_message_ptr& msg); - void bcast_hs_vote_msg(const hs_vote_message_ptr& msg); - void bcast_hs_new_view_msg(const hs_new_view_message_ptr& msg); - void bcast_hs_new_block_msg(const hs_new_block_message_ptr& msg); + void bcast_msg( send_buffer_type msg ); void add_unlinkable_block( signed_block_ptr b, const block_id_type& id ) { std::optional rm_blk_id = unlinkable_block_cache.add_unlinkable_block(std::move(b), id); @@ -497,10 +495,10 @@ namespace eosio { void transaction_ack(const std::pair&); void on_irreversible_block( const block_state_ptr& block ); - void on_hs_proposal_message( const hs_proposal_message_ptr& msg ); - void on_hs_vote_message( const hs_vote_message_ptr& msg ); - void on_hs_new_view_message( const hs_new_view_message_ptr& msg ); - void on_hs_new_block_message( const hs_new_block_message_ptr& msg ); + void on_hs_proposal_message( const hs_proposal_message& msg ); + void on_hs_vote_message( const hs_vote_message& msg ); + void on_hs_new_view_message( const hs_new_view_message& msg ); + void on_hs_new_block_message( const hs_new_block_message& msg ); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_expire_timer(); @@ -1715,8 +1713,6 @@ namespace eosio { //------------------------------------------------------------------------ - using send_buffer_type = std::shared_ptr>; - struct buffer_factory { /// caches result for subsequent calls, only provide same net_message instance for each invocation @@ -1817,7 +1813,7 @@ namespace eosio { } buffer_factory buff_factory; - auto send_buffer = buff_factory.get_send_buffer( m ); + const auto& send_buffer = buff_factory.get_send_buffer( m ); enqueue_buffer( send_buffer, close_after_send ); } @@ -1827,7 +1823,7 @@ namespace eosio { verify_strand_in_this_thread( strand, __func__, __LINE__ ); block_buffer_factory buff_factory; - auto sb = buff_factory.get_send_buffer( b ); + const auto& sb = buff_factory.get_send_buffer( b ); latest_blk_time = std::chrono::system_clock::now(); enqueue_buffer( sb, no_reason, to_sync_queue); } @@ -2560,53 +2556,12 @@ namespace eosio { } ); } - void dispatch_manager::bcast_hs_proposal_msg(const hs_proposal_message_ptr& msg) { - if( my_impl->sync_master->syncing_from_peer() ) return; - hs_proposal_message& msg_val = *(msg.get()); - my_impl->connections.for_each_block_connection( [&msg_val]( auto& cp ) { - if( !cp->current() ) return true; - cp->strand.post( [cp, msg_val]() { - if (cp->protocol_version >= proto_instant_finality) - cp->enqueue( msg_val ); - }); - return true; - } ); - } - - void dispatch_manager::bcast_hs_vote_msg(const hs_vote_message_ptr& msg) { - if( my_impl->sync_master->syncing_from_peer() ) return; - hs_vote_message& msg_val = *(msg.get()); - my_impl->connections.for_each_block_connection( [&msg_val]( auto& cp ) { - if( !cp->current() ) return true; - cp->strand.post( [cp, msg_val]() { - if (cp->protocol_version >= proto_instant_finality) - cp->enqueue( msg_val ); - }); - return true; - } ); - } - - void dispatch_manager::bcast_hs_new_block_msg(const hs_new_block_message_ptr& msg) { - if( my_impl->sync_master->syncing_from_peer() ) return; - hs_new_block_message& msg_val = *(msg.get()); - my_impl->connections.for_each_block_connection( [&msg_val]( auto& cp ) { - if( !cp->current() ) return true; - cp->strand.post( [cp, msg_val]() { - if (cp->protocol_version >= proto_instant_finality) - cp->enqueue( msg_val ); - }); - return true; - } ); - } - - void dispatch_manager::bcast_hs_new_view_msg(const hs_new_view_message_ptr& msg) { - if( my_impl->sync_master->syncing_from_peer() ) return; - hs_new_view_message& msg_val = *(msg.get()); - my_impl->connections.for_each_block_connection( [&msg_val]( auto& cp ) { + void dispatch_manager::bcast_msg( send_buffer_type msg ) { + my_impl->connections.for_each_block_connection( [msg{std::move(msg)}]( auto& cp ) { if( !cp->current() ) return true; - cp->strand.post( [cp, msg_val]() { + cp->strand.post( [cp, msg]() { if (cp->protocol_version >= proto_instant_finality) - cp->enqueue( msg_val ); + cp->enqueue_buffer( msg, no_reason ); }); return true; } ); @@ -3632,18 +3587,22 @@ namespace eosio { } void connection::handle_message( const hs_vote_message& msg ) { + peer_dlog(this, "received vote: ${msg}", ("msg", msg)); my_impl->chain_plug->notify_hs_vote_message(msg); } void connection::handle_message( const hs_proposal_message& msg ) { + peer_dlog(this, "received proposal: ${msg}", ("msg", msg)); my_impl->chain_plug->notify_hs_proposal_message(msg); } void connection::handle_message( const hs_new_view_message& msg ) { + peer_dlog(this, "received new view: ${msg}", ("msg", msg)); my_impl->chain_plug->notify_hs_new_view_message(msg); } void connection::handle_message( const hs_new_block_message& msg ) { + peer_dlog(this, "received new block msg: ${msg}", ("msg", msg)); my_impl->chain_plug->notify_hs_new_block_message(msg); } @@ -3898,44 +3857,48 @@ namespace eosio { on_active_schedule(chain_plug->chain().active_producers()); } - // called from application thread - void net_plugin_impl::on_hs_proposal_message( const hs_proposal_message_ptr& msg ){ - //ilog("network plugin received consensus message from application"); + void net_plugin_impl::on_hs_proposal_message( const hs_proposal_message& msg ) { + fc_dlog(logger, "sending proposal msg: ${msg}", ("msg", msg)); - dispatcher->strand.post( [this, msg]() { - dispatcher->bcast_hs_proposal_msg( msg ); - }); + buffer_factory buff_factory; + auto send_buffer = buff_factory.get_send_buffer( msg ); + dispatcher->strand.post( [this, msg{std::move(send_buffer)}]() mutable { + dispatcher->bcast_msg( std::move(msg) ); + }); } - // called from application thread - void net_plugin_impl::on_hs_vote_message( const hs_vote_message_ptr& msg ){ - //ilog("network plugin received confirmation message from application"); + void net_plugin_impl::on_hs_vote_message( const hs_vote_message& msg ) { + fc_dlog(logger, "sending vote msg: ${msg}", ("msg", msg)); - dispatcher->strand.post( [this, msg]() { - dispatcher->bcast_hs_vote_msg( msg ); - }); + buffer_factory buff_factory; + auto send_buffer = buff_factory.get_send_buffer( msg ); + dispatcher->strand.post( [this, msg{std::move(send_buffer)}]() mutable { + dispatcher->bcast_msg( std::move(msg) ); + }); } - // called from application thread - void net_plugin_impl::on_hs_new_view_message( const hs_new_view_message_ptr& msg ){ - //ilog("network plugin received new_view message from application"); + void net_plugin_impl::on_hs_new_view_message( const hs_new_view_message& msg ) { + fc_dlog(logger, "sending new_view msg: ${msg}", ("msg", msg)); - dispatcher->strand.post( [this, msg]() { - dispatcher->bcast_hs_new_view_msg( msg ); - }); + buffer_factory buff_factory; + auto send_buffer = buff_factory.get_send_buffer( msg ); + dispatcher->strand.post( [this, msg{std::move(send_buffer)}]() mutable { + dispatcher->bcast_msg( std::move(msg) ); + }); } - // called from application thread - void net_plugin_impl::on_hs_new_block_message( const hs_new_block_message_ptr& msg ){ - //ilog("network plugin received new_block message from application"); + void net_plugin_impl::on_hs_new_block_message( const hs_new_block_message& msg ) { + fc_dlog(logger, "sending new_block msg: ${msg}", ("msg", msg)); - dispatcher->strand.post( [this, msg]() { - dispatcher->bcast_hs_new_block_msg( msg ); - }); + buffer_factory buff_factory; + auto send_buffer = buff_factory.get_send_buffer( msg ); + dispatcher->strand.post( [this, msg{std::move(send_buffer)}]() mutable { + dispatcher->bcast_msg( std::move(msg) ); + }); } // called from application thread @@ -4262,6 +4225,21 @@ namespace eosio { chain_plug->enable_accept_transactions(); } + chain_plug->register_pacemaker_bcast_functions( + [my = shared_from_this()](const hs_proposal_message& s) { + my->on_hs_proposal_message(s); + }, + [my = shared_from_this()](const hs_vote_message& s) { + my->on_hs_vote_message(s); + }, + [my = shared_from_this()](const hs_new_block_message& s) { + my->on_hs_new_block_message(s); + }, + [my = shared_from_this()](const hs_new_view_message& s) { + my->on_hs_new_view_message(s); + } ); + + } FC_LOG_AND_RETHROW() } @@ -4322,19 +4300,6 @@ namespace eosio { my->on_irreversible_block( s ); } ); - cc.new_hs_proposal_message.connect( [my = shared_from_this()]( const hs_proposal_message_ptr& s ) { - my->on_hs_proposal_message( s ); - } ); - cc.new_hs_vote_message.connect( [my = shared_from_this()]( const hs_vote_message_ptr& s ) { - my->on_hs_vote_message( s ); - } ); - cc.new_hs_new_view_message.connect( [my = shared_from_this()]( const hs_new_view_message_ptr& s ) { - my->on_hs_new_view_message( s ); - } ); - cc.new_hs_new_block_message.connect( [my = shared_from_this()]( const hs_new_block_message_ptr& s ) { - my->on_hs_new_block_message( s ); - } ); - } { From 5f5ebe10bc82fe14d2c05b1a9ebdcd35059fe87f Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 25 Aug 2023 14:34:49 +0000 Subject: [PATCH 068/151] Fixed serialization / deserialization and checksum, key / signatures prefixes --- libraries/hotstuff/qc_chain.cpp | 40 ----------------- .../libfc/include/fc/crypto/bls_common.hpp | 43 +++++++++++++++++++ .../include/fc/crypto/bls_private_key.hpp | 5 ++- .../include/fc/crypto/bls_public_key.hpp | 2 - .../libfc/include/fc/crypto/bls_signature.hpp | 12 +----- .../libfc/src/crypto/bls_private_key.cpp | 19 ++++---- libraries/libfc/src/crypto/bls_public_key.cpp | 19 +++----- libraries/libfc/src/crypto/bls_signature.cpp | 15 ++----- libraries/libfc/src/crypto/bls_utils.cpp.old | 12 ------ 9 files changed, 67 insertions(+), 100 deletions(-) create mode 100644 libraries/libfc/include/fc/crypto/bls_common.hpp delete mode 100644 libraries/libfc/src/crypto/bls_utils.cpp.old diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 3bab42d27d..1493a3af62 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -1,45 +1,5 @@ #include -/* - - Todo list / notes: - - fork tests in unittests - - network plugin versioning - - handshake_message.network_version - - independant of protocol feature activation - - separate library for hotstuff (look at SHIP libray used by state history plugin ) - - boost tests producer plugin test - - regression tests python framework as a base - - performance testing - - complete proposer / leader differentiation - - integration with new bls implementation - - hotstuff as a library with its own tests (model on state history plugin + state_history library ) - - unit / integration tests -> producer_plugin + fork_tests tests as a model - - test deterministic sequence - - test non-replica participation - - test finality vioaltion - - test loss of liveness - - test split chain - - store schedules and transition view height, and prune on commit - - integration with fork_db / LIB overhaul - - integration with performance testing - - regression testing ci/cd -> python regression tests - - implement bitset for efficiency - - add APIs for proof data - - add election proposal in block header - - map proposers / finalizers / leader to new host functions - - support pause / resume producer - - keep track of proposals sent to peers - - allow syncing of proposals - - versioning of net protocol version - - protocol feature activation HOTSTUFF_CONSENSUS - - system contract update 1 - -- allow BPs to register + prove their aggregate pub key. - -- Allow existing BPs to unreg + reg without new aggregate key. - -- Prevent new BPs from registering without proving aggregate pub key - - system contract update 2 (once all or at least overwhelming majority of BPs added a bls key) - -- skip BPs without a bls key in the selection, new host functions are available -*/ // FIXME/REMOVE: remove all of this tracing diff --git a/libraries/libfc/include/fc/crypto/bls_common.hpp b/libraries/libfc/include/fc/crypto/bls_common.hpp new file mode 100644 index 0000000000..e071c5d505 --- /dev/null +++ b/libraries/libfc/include/fc/crypto/bls_common.hpp @@ -0,0 +1,43 @@ +#pragma once +#include + +namespace fc::crypto::blslib { + + template + static Container serialize_base58(const std::string& data_str) + { + + using wrapper = checksummed_data; + + wrapper wrapped; + + auto bin = fc::from_base58(data_str); + fc::datastream unpacker(bin.data(), bin.size()); + fc::raw::unpack(unpacker, wrapped); + FC_ASSERT(!unpacker.remaining(), "decoded base58 length too long"); + auto checksum = wrapper::calculate_checksum(wrapped.data, nullptr); + FC_ASSERT(checksum == wrapped.check); + + return wrapped.data; + } + + template + static std::string deserialize_base58( Container data, const yield_function_t& yield) { + + using wrapper = checksummed_data; + + wrapper wrapped; + + wrapped.data = data; + yield(); + wrapped.check = wrapper::calculate_checksum(wrapped.data, nullptr); + yield(); + auto packed = raw::pack( wrapped ); + yield(); + auto data_str = to_base58( packed.data(), packed.size(), yield ); + yield(); + + return data_str; + } + +} // fc::crypto::blslib diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 56bcdd49c0..09756101a6 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -8,12 +8,15 @@ namespace fc::crypto::blslib { namespace config { constexpr const char* bls_private_key_base_prefix = "PVT"; constexpr const char* bls_private_key_prefix = "BLS"; + //constexpr const char* bls_private_key_prefix[] = {"BLS"}; }; class bls_private_key { public: + using storage_type = std::variant>; + bls_private_key() = default; bls_private_key( bls_private_key&& ) = default; bls_private_key( const bls_private_key& ) = default; @@ -22,8 +25,6 @@ namespace fc::crypto::blslib { _seed = std::move(seed); } - // serialize to/from string - // TODO: determine format to use for string of private key explicit bls_private_key(const string& base58str); std::string to_string(const yield_function_t& yield = yield_function_t()) const; diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index 93535249d7..e0d52dac77 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -30,12 +30,10 @@ namespace fc::crypto::blslib { _pkey = pkey; } - // serialize to/from string explicit bls_public_key(const string& base58str); std::string to_string(const yield_function_t& yield = yield_function_t()) const; - //storage_type _storage; bls12_381::g1 _pkey; private: diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index 58390ce388..5fe4e2955d 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -16,7 +16,7 @@ namespace fc::crypto::blslib { constexpr const char* bls_signature_base_prefix = "SIG"; constexpr const char* bls_signature_prefix = "BLS"; }; - + class bls_signature { public: @@ -30,7 +30,6 @@ namespace fc::crypto::blslib { _sig = sig; } - // serialize to/from string explicit bls_signature(const string& base58str); std::string to_string(const yield_function_t& yield = yield_function_t()) const; @@ -53,15 +52,6 @@ namespace fc { void from_variant(const variant& var, crypto::blslib::bls_signature& vo); } // namespace fc -/*namespace std { - template <> struct hash { - std::size_t operator()(const crypto::blslib::bls_signature& k) const { - //return fc::crypto::hash_value(k); - return 0; - } - }; -} // std*/ - FC_REFLECT(bls12_381::fp, (d)) FC_REFLECT(bls12_381::fp2, (c0)(c1)) FC_REFLECT(bls12_381::g2, (x)(y)(z)) diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index b6c19fd688..866340b9cb 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace fc::crypto::blslib { @@ -32,22 +33,20 @@ namespace fc::crypto::blslib { const auto pivot = base58str.find('_'); FC_ASSERT(pivot != std::string::npos, "No delimiter in string, cannot determine data type: ${str}", ("str", base58str)); - const auto base_prefix_str = base58str.substr(0, 3); + const auto base_prefix_str = base58str.substr(0, 3); //pvt FC_ASSERT(config::bls_private_key_base_prefix == base_prefix_str, "BLS Private Key has invalid base prefix: ${str}", ("str", base58str)("base_prefix_str", base_prefix_str)); - const auto prefix_str = base58str.substr(pivot + 1, 3); + const auto prefix_str = base58str.substr(pivot + 1, 3); //bls FC_ASSERT(config::bls_private_key_prefix == prefix_str, "BLS Private Key has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str)); auto data_str = base58str.substr(8); - auto bytes = from_base58(data_str); + vector bytes = fc::crypto::blslib::serialize_base58>(data_str); - FC_ASSERT(bytes.size() == 32 ); + FC_ASSERT(bytes.size() == 32); - std::vector v2(32); - std::copy(bytes.begin(), bytes.end(), v2.begin()); + return bytes; - return v2; } bls_private_key::bls_private_key(const std::string& base58str) @@ -56,10 +55,10 @@ namespace fc::crypto::blslib { std::string bls_private_key::to_string(const yield_function_t& yield) const { + + string data_str = fc::crypto::blslib::deserialize_base58>(_seed, yield); - string pk = to_base58((const char*)&(_seed[0]), 32, yield); - - return std::string(config::bls_private_key_base_prefix) + "_" + std::string(config::bls_private_key_prefix) + "_" + pk; + return std::string(config::bls_private_key_base_prefix) + "_" + std::string(config::bls_private_key_prefix)+ "_" + data_str; } diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 865d96cf82..ee66197c15 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -1,10 +1,11 @@ #include #include #include +#include namespace fc::crypto::blslib { - static bls12_381::g1 parse_base58(const std::string& base58str) + static bls12_381::g1 pub_parse_base58(const std::string& base58str) { const auto pivot = base58str.find('_'); @@ -18,29 +19,23 @@ namespace fc::crypto::blslib { auto data_str = base58str.substr(8); - std::vector bytes = from_base58(data_str); - - FC_ASSERT(bytes.size() == 48); + std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); - std::array v2; - std::copy(bytes.begin(), bytes.end(), v2.begin()); - std::optional g1 = bls12_381::g1::fromCompressedBytesBE(v2); + std::optional g1 = bls12_381::g1::fromCompressedBytesBE(bytes); FC_ASSERT(g1); return *g1; } bls_public_key::bls_public_key(const std::string& base58str) - :_pkey(parse_base58(base58str)) + :_pkey(pub_parse_base58(base58str)) {} std::string bls_public_key::to_string(const yield_function_t& yield)const { - std::vector v2; std::array bytes = _pkey.toCompressedBytesBE(); - std::copy(bytes.begin(), bytes.end(), std::back_inserter(v2)); - std::string data_str = to_base58(v2, yield); - + std::string data_str = fc::crypto::blslib::deserialize_base58>(bytes, yield); + return std::string(config::bls_public_key_base_prefix) + "_" + std::string(config::bls_public_key_prefix) + "_" + data_str; } diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 53cc296a5b..0c474ec206 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -1,10 +1,10 @@ #include #include #include +#include namespace fc::crypto::blslib { - static bls12_381::g2 sig_parse_base58(const std::string& base58str) { try { @@ -19,14 +19,9 @@ namespace fc::crypto::blslib { auto data_str = base58str.substr(8); - std::vector bytes = from_base58(data_str); - - //std::vector v1 = from_base58(base58str); + std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); - FC_ASSERT(bytes.size() == 96); - std::array v2; - std::copy(bytes.begin(), bytes.end(), v2.begin()); - std::optional g2 = bls12_381::g2::fromCompressedBytesBE(v2); + std::optional g2 = bls12_381::g2::fromCompressedBytesBE(bytes); FC_ASSERT(g2); return *g2; } FC_RETHROW_EXCEPTIONS( warn, "error parsing bls_signature", ("str", base58str ) ) } @@ -38,11 +33,9 @@ namespace fc::crypto::blslib { std::string bls_signature::to_string(const yield_function_t& yield) const { - std::vector v2; std::array bytes = _sig.toCompressedBytesBE(); - std::copy(bytes.begin(), bytes.end(), std::back_inserter(v2)); - std::string data_str = to_base58(v2, yield); + std::string data_str = fc::crypto::blslib::deserialize_base58>(bytes, yield); return std::string(config::bls_signature_base_prefix) + "_" + std::string(config::bls_signature_prefix) + "_" + data_str; diff --git a/libraries/libfc/src/crypto/bls_utils.cpp.old b/libraries/libfc/src/crypto/bls_utils.cpp.old deleted file mode 100644 index 30aab8e3dd..0000000000 --- a/libraries/libfc/src/crypto/bls_utils.cpp.old +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include - -namespace fc { namespace crypto { namespace blslib { - - static bool verify( const blslib::bls_public_key &pubkey, - const vector &message, - const bls_signature &signature){ - - } - -} } } // fc::crypto::blslib From cf2920e95368ba37036e59cc4c7ab16f6f293293 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 25 Aug 2023 14:52:29 +0000 Subject: [PATCH 069/151] Changed private key storage type from vector to array to remove the need to recompute the private key everytime we sign --- .../include/fc/crypto/bls_private_key.hpp | 9 ++++----- libraries/libfc/src/crypto/bls_private_key.cpp | 18 ++++++++---------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 09756101a6..683cd38fae 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -15,14 +15,12 @@ namespace fc::crypto::blslib { { public: - using storage_type = std::variant>; - bls_private_key() = default; bls_private_key( bls_private_key&& ) = default; bls_private_key( const bls_private_key& ) = default; bls_private_key& operator=( const bls_private_key& ) = default; explicit bls_private_key( std::vector seed ) { - _seed = std::move(seed); + _sk = bls12_381::secret_key(seed); } explicit bls_private_key(const string& base58str); @@ -38,7 +36,8 @@ namespace fc::crypto::blslib { } private: - std::vector _seed; + //std::vector _seed; + std::array _sk; friend struct reflector; }; // bls_private_key @@ -51,4 +50,4 @@ namespace fc { void from_variant(const variant& var, crypto::blslib::bls_private_key& vo); } // namespace fc -FC_REFLECT(crypto::blslib::bls_private_key, (_seed) ) +FC_REFLECT(crypto::blslib::bls_private_key, (_sk) ) diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index 866340b9cb..53cb0e0922 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -9,15 +9,15 @@ namespace fc::crypto::blslib { bls_public_key bls_private_key::get_public_key() const { - auto sk = bls12_381::secret_key(_seed); - bls12_381::g1 pk = bls12_381::public_key(sk); + //auto sk = bls12_381::secret_key(_seed); + bls12_381::g1 pk = bls12_381::public_key(_sk); return bls_public_key(pk); } bls_signature bls_private_key::sign( const vector& message ) const { - std::array sk = bls12_381::secret_key(_seed); - bls12_381::g2 sig = bls12_381::sign(sk, message); + //std::array sk = bls12_381::secret_key(_seed); + bls12_381::g2 sig = bls12_381::sign(_sk, message); return bls_signature(sig); } @@ -27,7 +27,7 @@ namespace fc::crypto::blslib { return bls_private_key(v); } - static vector priv_parse_base58(const string& base58str) + static std::array priv_parse_base58(const string& base58str) { const auto pivot = base58str.find('_'); @@ -41,22 +41,20 @@ namespace fc::crypto::blslib { auto data_str = base58str.substr(8); - vector bytes = fc::crypto::blslib::serialize_base58>(data_str); - - FC_ASSERT(bytes.size() == 32); + std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); return bytes; } bls_private_key::bls_private_key(const std::string& base58str) - :_seed(priv_parse_base58(base58str)) + :_sk(priv_parse_base58(base58str)) {} std::string bls_private_key::to_string(const yield_function_t& yield) const { - string data_str = fc::crypto::blslib::deserialize_base58>(_seed, yield); + string data_str = fc::crypto::blslib::deserialize_base58>(_sk, yield); return std::string(config::bls_private_key_base_prefix) + "_" + std::string(config::bls_private_key_prefix)+ "_" + data_str; From 3cef6f10f5609817e40a16c83de8ba567fd05970 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 25 Aug 2023 14:53:50 +0000 Subject: [PATCH 070/151] Removed commented code --- libraries/libfc/include/fc/crypto/bls_private_key.hpp | 2 -- libraries/libfc/src/crypto/bls_private_key.cpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 683cd38fae..7a796039ff 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -8,7 +8,6 @@ namespace fc::crypto::blslib { namespace config { constexpr const char* bls_private_key_base_prefix = "PVT"; constexpr const char* bls_private_key_prefix = "BLS"; - //constexpr const char* bls_private_key_prefix[] = {"BLS"}; }; class bls_private_key @@ -36,7 +35,6 @@ namespace fc::crypto::blslib { } private: - //std::vector _seed; std::array _sk; friend struct reflector; diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index 53cb0e0922..db6297eea8 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -9,14 +9,12 @@ namespace fc::crypto::blslib { bls_public_key bls_private_key::get_public_key() const { - //auto sk = bls12_381::secret_key(_seed); bls12_381::g1 pk = bls12_381::public_key(_sk); return bls_public_key(pk); } bls_signature bls_private_key::sign( const vector& message ) const { - //std::array sk = bls12_381::secret_key(_seed); bls12_381::g2 sig = bls12_381::sign(_sk, message); return bls_signature(sig); } From 54129ed8c75c0d0274ae2bce0005bdb0819a5a77 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 25 Aug 2023 12:56:43 -0500 Subject: [PATCH 071/151] GH-1547 Support unlimited finalizers --- .../chain/include/eosio/chain/hotstuff.hpp | 38 ++++- .../include/eosio/hotstuff/qc_chain.hpp | 8 +- libraries/hotstuff/qc_chain.cpp | 133 +++++++++--------- libraries/hotstuff/test/test_hotstuff.cpp | 114 +++++++-------- 4 files changed, 159 insertions(+), 134 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index e51d6968fb..629d9333a0 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -6,6 +6,8 @@ #include #include +#include + namespace eosio::chain { const block_id_type NULL_BLOCK_ID = block_id_type("00"); @@ -21,10 +23,41 @@ namespace eosio::chain { }; struct quorum_certificate { + explicit quorum_certificate(uint32_t finalizer_size = 0) { + reset(NULL_PROPOSAL_ID, finalizer_size); + } + + void reset(const fc::sha256& proposal, uint32_t finalizer_size) { + proposal_id = proposal; + boost::dynamic_bitset b; + b.resize(finalizer_size); + boost::to_string(b, active_finalizers); + active_agg_sig = fc::crypto::blslib::bls_signature(); + quorum_met = false; + } + + auto get_active_finalizers() const { + assert(!active_finalizers.empty()); + return boost::dynamic_bitset(active_finalizers); + } + void set_active_finalizers(const auto& bs) { + assert(!bs.empty()); + boost::to_string(bs, active_finalizers); + } + const std::string& get_active_finalizers_string() const { return active_finalizers; } + + const fc::sha256& get_proposal_id() const { return proposal_id; } + const fc::crypto::blslib::bls_signature& get_active_agg_sig() const { return active_agg_sig; } + void set_active_agg_sig( const fc::crypto::blslib::bls_signature& sig) { active_agg_sig = sig; } + bool is_quorum_met() const { return quorum_met; } + void set_quorum_met() { quorum_met = true; } + + private: + friend struct fc::reflector; fc::sha256 proposal_id = NULL_PROPOSAL_ID; - fc::unsigned_int active_finalizers = 0; //bitset encoding, following canonical order + std::string active_finalizers; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; - bool quorum_met = false; + bool quorum_met = false; // not serialized across network }; struct hs_vote_message { @@ -84,6 +117,7 @@ namespace eosio::chain { } //eosio::chain +// // @ignore quorum_met FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); FC_REFLECT(eosio::chain::extended_schedule, (producer_schedule)(bls_pub_keys)); FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 7918d68865..cfb340de3e 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -61,15 +61,15 @@ namespace eosio::hotstuff { // returns false if proposal with that same ID already exists at the store of its height bool insert_proposal(const hs_proposal_message& proposal); - uint32_t positive_bits_count(fc::unsigned_int value); + uint32_t positive_bits_count(const boost::dynamic_bitset<>& finalizers); - fc::unsigned_int update_bitset(fc::unsigned_int value, name finalizer); + boost::dynamic_bitset<> update_bitset(const boost::dynamic_bitset<>& finalizer_set, name finalizer); digest_type get_digest_to_sign(const block_id_type& block_id, uint8_t phase_counter, const fc::sha256& final_on_qc); //get digest to sign from proposal data void reset_qc(const fc::sha256& proposal_id); //reset current internal qc - bool evaluate_quorum(const extended_schedule& es, fc::unsigned_int finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal + bool evaluate_quorum(const extended_schedule& es, const boost::dynamic_bitset<>& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal // qc.quorum_met has to be updated by the caller (if it wants to) based on the return value of this method bool is_quorum_met(const eosio::chain::quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal); //check if quorum has been met over a proposal @@ -137,8 +137,6 @@ namespace eosio::hotstuff { eosio::chain::extended_schedule _schedule; base_pacemaker* _pacemaker = nullptr; std::set _my_producers; - bool _log = true; - bool _errors = true; name _id; mutable std::atomic _state_version = 1; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 94d43cdb2b..83859c57b2 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -128,32 +128,22 @@ namespace eosio { namespace hotstuff { #endif } - uint32_t qc_chain::positive_bits_count(fc::unsigned_int value){ - boost::dynamic_bitset b(21, value); - uint32_t count = 0; - for (boost::dynamic_bitset<>::size_type i = 0; i < b.size(); i++){ - if (b[i]==true)count++; - } - return count; + uint32_t qc_chain::positive_bits_count(const boost::dynamic_bitset<>& finalizers) { + return finalizers.count(); // the number of bits in this bitset that are set. } - fc::unsigned_int qc_chain::update_bitset(fc::unsigned_int value, name finalizer ) { - - fc_tlog(_logger, " === update bitset ${value} ${finalizer}", - ("value", value) - ("finalizer", finalizer)); + boost::dynamic_bitset<> qc_chain::update_bitset(const boost::dynamic_bitset<>& finalizer_set, name finalizer ) { - boost::dynamic_bitset b( 21, value ); + boost::dynamic_bitset b( finalizer_set ); vector finalizers = _pacemaker->get_finalizers(); for (size_t i = 0; i < finalizers.size();i++) { if (finalizers[i] == finalizer) { b.flip(i); fc_tlog(_logger, " === finalizer found ${finalizer} new value : ${value}", - ("finalizer", finalizer) - ("value", b.to_ulong())); + ("finalizer", finalizer)("value", [&](){ std::string r; boost::to_string(b, r); return r; }())); - return b.to_ulong(); + return b; } } fc_tlog(_logger, " *** finalizer not found ${finalizer}", @@ -173,10 +163,10 @@ namespace eosio { namespace hotstuff { b2 = get_proposal( proposal_id ); if (b2 != nullptr) { ret_arr.push_back( *b2 ); - b1 = get_proposal( b2->justify.proposal_id ); + b1 = get_proposal( b2->justify.get_proposal_id() ); if (b1 != nullptr) { ret_arr.push_back( *b1 ); - b = get_proposal( b1->justify.proposal_id ); + b = get_proposal( b1->justify.get_proposal_id() ); if (b != nullptr) ret_arr.push_back( *b ); } @@ -190,8 +180,8 @@ namespace eosio { namespace hotstuff { b_new.parent_id = _b_leaf; b_new.phase_counter = phase_counter; b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ - std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); + if (b_new.justify.get_proposal_id() != NULL_PROPOSAL_ID){ + std::vector current_qc_chain = get_qc_chain(b_new.justify.get_proposal_id()); size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); if (chain_length>=2){ auto itr = current_qc_chain.begin(); @@ -219,17 +209,14 @@ namespace eosio { namespace hotstuff { ("phase_counter", b_new.phase_counter) ("proposal_id", b_new.proposal_id) ("parent_id", b_new.parent_id) - ("justify", b_new.justify.proposal_id)); + ("justify", b_new.justify.get_proposal_id())); return b_new; } - void qc_chain::reset_qc(const fc::sha256& proposal_id){ + void qc_chain::reset_qc(const fc::sha256& proposal_id) { fc_tlog(_logger, " === ${id} resetting qc : ${proposal_id}", ("proposal_id" , proposal_id)("id", _id)); - _current_qc.proposal_id = proposal_id; - _current_qc.quorum_met = false; - _current_qc.active_finalizers = 0; - _current_qc.active_agg_sig = fc::crypto::blslib::bls_signature(); + _current_qc.reset(proposal_id, 21); // TODO: use active schedule size } hs_new_block_message qc_chain::new_block_candidate(const block_id_type& block_id) { @@ -239,7 +226,7 @@ namespace eosio { namespace hotstuff { return b; } - bool qc_chain::evaluate_quorum(const extended_schedule & es, fc::unsigned_int finalizers, const fc::crypto::blslib::bls_signature & agg_sig, const hs_proposal_message & proposal){ + bool qc_chain::evaluate_quorum(const extended_schedule& es, const boost::dynamic_bitset<>& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal) { bool first = true; @@ -247,17 +234,17 @@ namespace eosio { namespace hotstuff { return false; } - boost::dynamic_bitset fb(21, finalizers.value); fc::crypto::blslib::bls_public_key agg_key; - for (boost::dynamic_bitset<>::size_type i = 0; i < fb.size(); i++) { - if (fb[i] == 1){ + for (boost::dynamic_bitset<>::size_type i = 0; i < finalizers.size(); i++) { + if (finalizers[i] == 1){ //adding finalizer's key to the aggregate pub key if (first) { first = false; agg_key = _private_key.get_public_key(); + } else { + agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key()}); } - else agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key() }); } } #warning fix todo @@ -278,16 +265,16 @@ namespace eosio { namespace hotstuff { return ok; } - bool qc_chain::is_quorum_met(const eosio::chain::quorum_certificate & qc, const extended_schedule & schedule, const hs_proposal_message & proposal){ + bool qc_chain::is_quorum_met(const eosio::chain::quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal) { - if (qc.quorum_met) { + if (qc.is_quorum_met()) { return true; //skip evaluation if we've already verified quorum was met } else { fc_tlog(_logger, " === qc : ${qc}", ("qc", qc)); // If the caller wants to update the quorum_met flag on its "qc" object, it will have to do so // based on the return value of this method, since "qc" here is const. - return evaluate_quorum(schedule, qc.active_finalizers, qc.active_agg_sig, proposal); + return evaluate_quorum(schedule, qc.get_active_finalizers(), qc.get_active_agg_sig(), proposal); } } @@ -298,6 +285,9 @@ namespace eosio { namespace hotstuff { _my_producers(std::move(my_producers)), _logger(logger) { + _high_qc.reset(NULL_PROPOSAL_ID, 21); // TODO: use active schedule size + _current_qc.reset(NULL_PROPOSAL_ID, 21); // TODO: use active schedule size + fc_dlog(_logger, " === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); } @@ -344,11 +334,11 @@ namespace eosio { namespace hotstuff { //auto start = fc::time_point::now(); - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID){ + if (proposal.justify.get_proposal_id() != NULL_PROPOSAL_ID){ - const hs_proposal_message *jp = get_proposal( proposal.justify.proposal_id ); + const hs_proposal_message *jp = get_proposal( proposal.justify.get_proposal_id() ); if (jp == nullptr) { - fc_elog(_logger, " *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); + fc_elog(_logger, " *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.get_proposal_id())); return; //can't recognize a proposal with an unknown justification } } @@ -358,13 +348,13 @@ namespace eosio { namespace hotstuff { fc_elog(_logger, " *** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); - if (p->justify.proposal_id != proposal.justify.proposal_id) { + if (p->justify.get_proposal_id() != proposal.justify.get_proposal_id()) { fc_elog(_logger, " *** ${id} two identical proposals (${proposal_id}) have different justifications : ${justify_1} vs ${justify_2}", ("id",_id) ("proposal_id", proposal.proposal_id) - ("justify_1", p->justify.proposal_id) - ("justify_2", proposal.justify.proposal_id)); + ("justify_1", p->justify.get_proposal_id()) + ("justify_2", proposal.justify.get_proposal_id())); } @@ -413,7 +403,7 @@ namespace eosio { namespace hotstuff { ("phase_counter", proposal.phase_counter) ("proposal_id", proposal.proposal_id) ("parent_id", proposal.parent_id) - ("justify", proposal.justify.proposal_id)); + ("justify", proposal.justify.get_proposal_id())); bool success = insert_proposal( proposal ); EOS_ASSERT( success , chain_exception, "internal error: duplicate proposal insert attempt" ); // can't happen unless bad mutex somewhere; already checked for this @@ -487,9 +477,10 @@ namespace eosio { namespace hotstuff { if (!am_leader) return; - fc_tlog(_logger, " === Process vote from ${finalizer} : current bitset ${value}" , ("finalizer", vote.finalizer)("value", _current_qc.active_finalizers)); + fc_tlog(_logger, " === Process vote from ${finalizer} : current bitset ${value}" , + ("finalizer", vote.finalizer)("value", _current_qc.get_active_finalizers_string())); // only leader need to take action on votes - if (vote.proposal_id != _current_qc.proposal_id) + if (vote.proposal_id != _current_qc.get_proposal_id()) return; const hs_proposal_message *p = get_proposal( vote.proposal_id ); @@ -498,19 +489,21 @@ namespace eosio { namespace hotstuff { return; } - bool quorum_met = _current_qc.quorum_met; //check if quorum already met + bool quorum_met = _current_qc.is_quorum_met(); //check if quorum already met // If quorum is already met, we don't need to do anything else. Otherwise, we aggregate the signature. if (!quorum_met){ auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); - if (_current_qc.active_finalizers>0) - _current_qc.active_agg_sig = fc::crypto::blslib::aggregate({_current_qc.active_agg_sig, vote.sig }); + boost::dynamic_bitset finalizer_set = _current_qc.get_active_finalizers(); + if (finalizer_set.any()) + _current_qc.set_active_agg_sig(fc::crypto::blslib::aggregate({_current_qc.get_active_agg_sig(), vote.sig })); else - _current_qc.active_agg_sig = vote.sig; + _current_qc.set_active_agg_sig(vote.sig); - _current_qc.active_finalizers = update_bitset(_current_qc.active_finalizers, vote.finalizer); + fc_tlog(_logger, " === update bitset ${value} ${finalizer}", ("value", _current_qc.get_active_finalizers_string())("finalizer", vote.finalizer)); + _current_qc.set_active_finalizers(update_bitset(finalizer_set, vote.finalizer)); quorum_met = is_quorum_met(_current_qc, _schedule, *p); @@ -522,7 +515,7 @@ namespace eosio { namespace hotstuff { ("proposal_id", vote.proposal_id) ("id", _id)); - _current_qc.quorum_met = true; + _current_qc.set_quorum_met(); //fc_tlog(_logger, " === update_high_qc : _current_qc ==="); update_high_qc(_current_qc); @@ -588,12 +581,12 @@ namespace eosio { namespace hotstuff { auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); - if (_current_qc.proposal_id != NULL_PROPOSAL_ID && _current_qc.quorum_met == false) { + if (_current_qc.get_proposal_id() != NULL_PROPOSAL_ID && _current_qc.is_quorum_met() == false) { fc_tlog(_logger, " === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", ("id", _id) - ("proposal_id", _current_qc.proposal_id) - ("quorum_met", _current_qc.quorum_met)); + ("proposal_id", _current_qc.get_proposal_id()) + ("quorum_met", _current_qc.is_quorum_met())); fc_tlog(_logger, " === ${id} setting _pending_proposal_block to ${block_id} (on_beat)", ("id", _id)("block_id", msg.block_id)); _pending_proposal_block = msg.block_id; @@ -602,8 +595,8 @@ namespace eosio { namespace hotstuff { fc_tlog(_logger, " === ${id} preparing new proposal ${proposal_id} : quorum met ${quorum_met}", ("id", _id) - ("proposal_id", _current_qc.proposal_id) - ("quorum_met", _current_qc.quorum_met)); + ("proposal_id", _current_qc.get_proposal_id()) + ("quorum_met", _current_qc.is_quorum_met())); hs_proposal_message proposal_candidate = new_proposal_candidate( msg.block_id, 0 ); reset_qc(proposal_candidate.proposal_id); @@ -715,20 +708,20 @@ namespace eosio { namespace hotstuff { // returns true on state change (caller decides update on state version bool qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ - fc_tlog(_logger, " === check to update high qc ${proposal_id}", ("proposal_id", high_qc.proposal_id)); + fc_tlog(_logger, " === check to update high qc ${proposal_id}", ("proposal_id", high_qc.get_proposal_id())); // if new high QC is higher than current, update to new - if (_high_qc.proposal_id == NULL_PROPOSAL_ID){ + if (_high_qc.get_proposal_id() == NULL_PROPOSAL_ID){ _high_qc = high_qc; - _b_leaf = _high_qc.proposal_id; + _b_leaf = _high_qc.get_proposal_id(); - fc_tlog(_logger, " === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); + fc_tlog(_logger, " === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.get_proposal_id())("id", _id)); return true; } else { - const hs_proposal_message *old_high_qc_prop = get_proposal( _high_qc.proposal_id ); - const hs_proposal_message *new_high_qc_prop = get_proposal( high_qc.proposal_id ); + const hs_proposal_message *old_high_qc_prop = get_proposal( _high_qc.get_proposal_id() ); + const hs_proposal_message *new_high_qc_prop = get_proposal( high_qc.get_proposal_id() ); if (old_high_qc_prop == nullptr) return false; if (new_high_qc_prop == nullptr) @@ -742,10 +735,10 @@ namespace eosio { namespace hotstuff { fc_tlog(_logger, " === updated high qc, now is : #${get_height} ${proposal_id}", ("get_height", new_high_qc_prop->get_height())("proposal_id", new_high_qc_prop->proposal_id)); _high_qc = high_qc; - _high_qc.quorum_met = true; - _b_leaf = _high_qc.proposal_id; + _high_qc.set_quorum_met(); + _b_leaf = _high_qc.get_proposal_id(); - fc_tlog(_logger, " === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.proposal_id)("id", _id)); + fc_tlog(_logger, " === ${id} _b_leaf updated (update_high_qc) : ${proposal_id}", ("proposal_id", _high_qc.get_proposal_id())("id", _id)); return true; } } @@ -793,11 +786,11 @@ namespace eosio { namespace hotstuff { fc::sha256 upcoming_commit; - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) + if (proposal.justify.get_proposal_id() == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated else { - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + std::vector current_qc_chain = get_qc_chain(proposal.justify.get_proposal_id()); size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); @@ -840,13 +833,13 @@ namespace eosio { namespace hotstuff { } //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) { + if (proposal.justify.get_proposal_id() == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) { liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated } else { const hs_proposal_message *b_lock = get_proposal( _b_lock ); EOS_ASSERT( b_lock != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", _b_lock) ); - const hs_proposal_message *prop_justification = get_proposal( proposal.justify.proposal_id ); - EOS_ASSERT( prop_justification != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", proposal.justify.proposal_id) ); + const hs_proposal_message *prop_justification = get_proposal( proposal.justify.get_proposal_id() ); + EOS_ASSERT( prop_justification != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", proposal.justify.get_proposal_id()) ); if (prop_justification->get_height() > b_lock->get_height()) { liveness_check = true; @@ -903,12 +896,12 @@ namespace eosio { namespace hotstuff { void qc_chain::update(const hs_proposal_message & proposal){ //fc_tlog(_logger, " === update internal state ==="); //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ + if (proposal.justify.get_proposal_id() == NULL_PROPOSAL_ID){ fc_dlog(_logger, " === ${id} proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)("id", _id)); return; } - std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); + std::vector current_qc_chain = get_qc_chain(proposal.justify.get_proposal_id()); size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index cba5789a39..e5adbd4e1a 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -120,14 +120,14 @@ class hotstuff_test_handler { finalizer_state fs; qcc.get_state(fs); const hs_proposal_message *leaf = fs.get_proposal( fs.b_leaf ); - const hs_proposal_message *qc = fs.get_proposal( fs.high_qc.proposal_id ); + const hs_proposal_message *qc = fs.get_proposal( fs.high_qc.get_proposal_id() ); const hs_proposal_message *lock = fs.get_proposal( fs.b_lock ); const hs_proposal_message *exec = fs.get_proposal( fs.b_exec ); if (leaf != nullptr) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << fs.b_leaf.str() << " block_num : " << leaf->block_num() << ", phase : " << unsigned(leaf->phase_counter) << "\n"; else std::cout << " - No b_leaf value " << "\n"; - if (qc != nullptr) std::cout << " - " << bp.to_string() << " current high_qc is : " << fs.high_qc.proposal_id.str() << " block_num : " << qc->block_num() << ", phase : " << unsigned(qc->phase_counter) << "\n"; + if (qc != nullptr) std::cout << " - " << bp.to_string() << " current high_qc is : " << fs.high_qc.get_proposal_id().str() << " block_num : " << qc->block_num() << ", phase : " << unsigned(qc->phase_counter) << "\n"; else std::cout << " - No high_qc value " << "\n"; if (lock != nullptr) std::cout << " - " << bp.to_string() << " current _b_lock is : " << fs.b_lock.str() << " block_num : " << lock->block_num() << ", phase : " << unsigned(lock->phase_counter) << "\n"; @@ -207,7 +207,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -237,7 +237,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -251,7 +251,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -261,7 +261,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -271,7 +271,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); @@ -281,7 +281,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); @@ -289,13 +289,13 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); //check bpb as well qcc_bpb->second->get_state(fs_bpb); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); @@ -333,7 +333,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -355,7 +355,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -365,7 +365,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -377,7 +377,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -387,13 +387,13 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); //check bpb as well qcc_bpb->second->get_state(fs_bpb); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -434,7 +434,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -444,7 +444,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -466,7 +466,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -483,7 +483,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -493,7 +493,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -503,7 +503,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -513,19 +513,19 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpa as well qcc_bpa->second->get_state(fs_bpa); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpc as well qcc_bpc->second->get_state(fs_bpc); - BOOST_CHECK_EQUAL(fs_bpc.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpc.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpc.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpc.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); @@ -566,7 +566,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -576,7 +576,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -596,7 +596,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -608,7 +608,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -634,7 +634,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, ""); qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -645,7 +645,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, ""); qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -656,7 +656,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, ""); qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -668,20 +668,20 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); //ht.print_bp_state("bpb"_n, ""); //check bpa as well qcc_bpb->second->get_state(fs_bpb); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); //ht.print_bp_state("bpi"_n, ""); qcc_bpi->second->get_state(fs_bpi); - BOOST_CHECK_EQUAL(fs_bpi.high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpi.high_qc.get_proposal_id().str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(fs_bpi.b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpi.b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); @@ -776,7 +776,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -790,7 +790,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -804,7 +804,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -818,7 +818,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -838,7 +838,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -852,7 +852,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); @@ -866,7 +866,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); @@ -880,7 +880,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); @@ -923,7 +923,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -933,7 +933,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -943,7 +943,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -955,7 +955,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -974,7 +974,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -984,7 +984,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -994,7 +994,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -1004,19 +1004,19 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpa as well qcc_bpa->second->get_state(fs_bpa); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpc as well qcc_bpc->second->get_state(fs_bpc); - BOOST_CHECK_EQUAL(fs_bpc.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpc.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpc.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpc.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); From dcb04cbcaf7b9e374ab6d24d8e604ab160f3d0d7 Mon Sep 17 00:00:00 2001 From: fcecin Date: Fri, 25 Aug 2023 15:31:10 -0300 Subject: [PATCH 072/151] set_finalizers host function (#1511) Work in progress. - Implemented host function (not tested); - Finalizer set types; - Placeholders for fc::crypto::blslib::bls_public_key operators == != and <; - Stub notify_set_finalizers signal to be connected to chain_plugin, to reach chain_pacemaker --- libraries/chain/controller.cpp | 8 + .../chain/include/eosio/chain/config.hpp | 4 + .../chain/include/eosio/chain/controller.hpp | 5 + .../include/eosio/chain/finalizer_set.hpp | 144 ++++++++++++++++++ .../eosio/chain/webassembly/interface.hpp | 9 ++ libraries/chain/webassembly/privileged.cpp | 30 ++++ .../include/fc/crypto/bls_public_key.hpp | 7 +- 7 files changed, 204 insertions(+), 3 deletions(-) create mode 100644 libraries/chain/include/eosio/chain/finalizer_set.hpp diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 037dc6de50..b0feb1c9f3 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1990,6 +1990,10 @@ struct controller_impl { emit( self.new_hs_new_block_message, msg ); } + void set_finalizers_impl(uint64_t fthreshold, vector 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 @@ -3313,6 +3317,10 @@ int64_t controller::set_proposed_producers( vector producers return version; } +void controller::set_finalizers( uint64_t fthreshold, vector finalizers ) { + my->set_finalizers_impl(fthreshold, finalizers); +} + const producer_authority_schedule& controller::active_producers()const { if( !(my->pending) ) return my->head->active_schedule; diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index 6448c6ae59..c3f91d9cbe 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -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 diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 934ed25dac..c75a3aa419 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -10,6 +10,8 @@ #include #include +#include + namespace chainbase { class database; } @@ -306,6 +308,8 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector producers ); + void set_finalizers( uint64_t fthreshold, vector finalizers ); + bool light_validation_allowed() const; bool skip_auth_check()const; bool skip_trx_checks()const; @@ -356,6 +360,7 @@ namespace eosio { namespace chain { signal new_hs_vote_message; signal new_hs_new_view_message; signal new_hs_new_block_message; + signal&>)> notify_set_finalizers; /* signal pre_apply_block; diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp new file mode 100644 index 0000000000..5a6123617e --- /dev/null +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -0,0 +1,144 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace eosio::chain { + + struct shared_finalizer_authority { + 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; + }; + + struct shared_finalizer_set { + shared_finalizer_set() = delete; + + explicit shared_finalizer_set( chainbase::allocator 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 finalizers; + }; + + struct finalizer_authority { + + name finalizer_name; + 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 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; + + 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 finalizers ) + :version(version) + ,fthreshold(fthreshold) + ,finalizers(finalizers) + {} + + auto to_shared(chainbase::allocator 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 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) ) diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index 59fac5078a..28528e33f6 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -173,6 +173,15 @@ namespace webassembly { */ int64_t set_proposed_producers_ex(uint64_t packed_producer_format, legacy_span 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 packed_finalizer_set); + /** * Retrieve the blockchain config parameters. * diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index f9a8456745..c985fed132 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -150,6 +151,35 @@ namespace eosio { namespace chain { namespace webassembly { } } + void interface::set_finalizers(legacy_span 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 ds( packed_finalizer_set.data(), packed_finalizer_set.size() ); + finalizer_set finset; + fc::raw::unpack(ds, finset); + vector & 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 unique_finalizer_keys; + std::set 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" ); + 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 packed_blockchain_parameters ) const { auto& gpo = context.control.get_global_properties(); diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index b805252de3..79b83d51a7 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -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; friend class bls_private_key; }; // bls_public_key From 44f76c497c71644da5827ca67babcff87dcfbe71 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 25 Aug 2023 19:35:42 +0000 Subject: [PATCH 073/151] Fixed prefix verfication + various cosmetic / style improvements --- .../include/fc/crypto/bls_private_key.hpp | 16 +++++----- .../include/fc/crypto/bls_public_key.hpp | 15 ++++------ .../libfc/include/fc/crypto/bls_signature.hpp | 14 ++++----- .../libfc/include/fc/crypto/bls_utils.hpp | 10 +++---- .../libfc/src/crypto/bls_private_key.cpp | 25 +++++----------- libraries/libfc/src/crypto/bls_public_key.cpp | 16 ++++------ libraries/libfc/src/crypto/bls_signature.cpp | 30 ++++++++----------- libraries/libfc/src/crypto/bls_utils.cpp | 10 +++---- libraries/libfc/test/test_bls.cpp | 10 +++---- 9 files changed, 60 insertions(+), 86 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 7a796039ff..30ad4a254e 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -6,8 +6,7 @@ namespace fc::crypto::blslib { namespace config { - constexpr const char* bls_private_key_base_prefix = "PVT"; - constexpr const char* bls_private_key_prefix = "BLS"; + constexpr std::string_view bls_private_key_prefix = "PVT_BLS_"; }; class bls_private_key @@ -17,20 +16,21 @@ namespace fc::crypto::blslib { bls_private_key() = default; bls_private_key( bls_private_key&& ) = default; bls_private_key( const bls_private_key& ) = default; - bls_private_key& operator=( const bls_private_key& ) = default; - explicit bls_private_key( std::vector seed ) { + explicit bls_private_key(const std::vector& seed ) { _sk = bls12_381::secret_key(seed); } - explicit bls_private_key(const string& base58str); + bls_private_key& operator=( const bls_private_key& ) = default; + + explicit bls_private_key(const std::string& base58str); std::string to_string(const yield_function_t& yield = yield_function_t()) const; bls_public_key get_public_key() const; - bls_signature sign( const vector& message ) const; + bls_signature sign( const std::vector& message ) const; static bls_private_key generate(); - static bls_private_key regenerate( vector seed ) { + static bls_private_key regenerate( std::vector seed ) { return bls_private_key(std::move(seed)); } @@ -48,4 +48,4 @@ namespace fc { void from_variant(const variant& var, crypto::blslib::bls_private_key& vo); } // namespace fc -FC_REFLECT(crypto::blslib::bls_private_key, (_sk) ) +FC_REFLECT(crypto::blslib::bls_private_key, (_sk) ) \ No newline at end of file diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index e0d52dac77..03301cb580 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -10,11 +10,8 @@ namespace fc::crypto::blslib { - using namespace std; - namespace config { - constexpr const char* bls_public_key_base_prefix = "PUB"; - constexpr const char* bls_public_key_prefix = "BLS"; + constexpr std::string_view bls_public_key_prefix = "PUB_BLS_"; }; class bls_public_key @@ -24,21 +21,19 @@ namespace fc::crypto::blslib { bls_public_key() = default; bls_public_key( bls_public_key&& ) = default; bls_public_key( const bls_public_key& ) = default; - bls_public_key& operator= (const bls_public_key& ) = default; - - bls_public_key( bls12_381::g1 pkey ){ + bls_public_key( const bls12_381::g1& pkey ){ _pkey = pkey; } - explicit bls_public_key(const string& base58str); + bls_public_key& operator= (const bls_public_key& ) = default; + + explicit bls_public_key(const std::string& base58str); std::string to_string(const yield_function_t& yield = yield_function_t()) const; bls12_381::g1 _pkey; private: - - friend std::ostream& operator<< (std::ostream& s, const bls_public_key& k); friend struct reflector; friend class bls_private_key; diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index 5fe4e2955d..b4abe0906e 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -10,11 +10,8 @@ namespace fc::crypto::blslib { - using namespace std; - namespace config { - constexpr const char* bls_signature_base_prefix = "SIG"; - constexpr const char* bls_signature_prefix = "BLS"; + constexpr std::string_view bls_signature_prefix = "SIG_BLS_"; }; class bls_signature @@ -24,13 +21,14 @@ namespace fc::crypto::blslib { bls_signature() = default; bls_signature( bls_signature&& ) = default; bls_signature( const bls_signature& ) = default; - bls_signature& operator= (const bls_signature& ) = default; - - bls_signature( bls12_381::g2 sig ){ + bls_signature( const bls12_381::g2& sig ){ _sig = sig; } - explicit bls_signature(const string& base58str); + bls_signature& operator= (const bls_signature& ) = default; + + + explicit bls_signature(const std::string& base58str); std::string to_string(const yield_function_t& yield = yield_function_t()) const; diff --git a/libraries/libfc/include/fc/crypto/bls_utils.hpp b/libraries/libfc/include/fc/crypto/bls_utils.hpp index 1f59aee7ff..886d84a825 100644 --- a/libraries/libfc/include/fc/crypto/bls_utils.hpp +++ b/libraries/libfc/include/fc/crypto/bls_utils.hpp @@ -6,15 +6,15 @@ namespace fc::crypto::blslib { bool verify(const bls_public_key& pubkey, - const vector& message, + const std::vector& message, const bls_signature& signature); - bls_public_key aggregate(const vector& keys); + bls_public_key aggregate(const std::vector& keys); - bls_signature aggregate(const vector& signatures); + bls_signature aggregate(const std::vector& signatures); - bool aggregate_verify(const vector& pubkeys, - const vector>& messages, + bool aggregate_verify(const std::vector& pubkeys, + const std::vector>& messages, const bls_signature& signature); } // fc::crypto::blslib diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index db6297eea8..bcce24cbf2 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -13,7 +13,7 @@ namespace fc::crypto::blslib { return bls_public_key(pk); } - bls_signature bls_private_key::sign( const vector& message ) const + bls_signature bls_private_key::sign( const std::vector& message ) const { bls12_381::g2 sig = bls12_381::sign(_sk, message); return bls_signature(sig); @@ -25,24 +25,17 @@ namespace fc::crypto::blslib { return bls_private_key(v); } - static std::array priv_parse_base58(const string& base58str) + static std::array priv_parse_base58(const std::string& base58str) { + auto res = std::mismatch(config::bls_private_key_prefix.begin(), config::bls_private_key_prefix.end(), + base58str.begin()); + FC_ASSERT(res.first == config::bls_private_key_prefix.end(), "BLS Private Key has invalid format : ${str}", ("str", base58str)); - const auto pivot = base58str.find('_'); - FC_ASSERT(pivot != std::string::npos, "No delimiter in string, cannot determine data type: ${str}", ("str", base58str)); - - const auto base_prefix_str = base58str.substr(0, 3); //pvt - FC_ASSERT(config::bls_private_key_base_prefix == base_prefix_str, "BLS Private Key has invalid base prefix: ${str}", ("str", base58str)("base_prefix_str", base_prefix_str)); - - const auto prefix_str = base58str.substr(pivot + 1, 3); //bls - FC_ASSERT(config::bls_private_key_prefix == prefix_str, "BLS Private Key has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str)); - - auto data_str = base58str.substr(8); + auto data_str = base58str.substr(config::bls_private_key_prefix.size()); std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); return bytes; - } bls_private_key::bls_private_key(const std::string& base58str) @@ -51,11 +44,9 @@ namespace fc::crypto::blslib { std::string bls_private_key::to_string(const yield_function_t& yield) const { - - string data_str = fc::crypto::blslib::deserialize_base58>(_sk, yield); + std::string data_str = fc::crypto::blslib::deserialize_base58>(_sk, yield); - return std::string(config::bls_private_key_base_prefix) + "_" + std::string(config::bls_private_key_prefix)+ "_" + data_str; - + return std::string(config::bls_private_key_prefix) + data_str; } } // fc::crypto::blslib diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index ee66197c15..34f4d869f3 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -7,17 +7,11 @@ namespace fc::crypto::blslib { static bls12_381::g1 pub_parse_base58(const std::string& base58str) { - - const auto pivot = base58str.find('_'); - FC_ASSERT(pivot != std::string::npos, "No delimiter in string, cannot determine data type: ${str}", ("str", base58str)); - - const auto base_prefix_str = base58str.substr(0, 3); - FC_ASSERT(config::bls_public_key_base_prefix == base_prefix_str, "BLS Public Key has invalid base prefix: ${str}", ("str", base58str)("base_prefix_str", base_prefix_str)); - - const auto prefix_str = base58str.substr(pivot + 1, 3); - FC_ASSERT(config::bls_public_key_prefix == prefix_str, "BLS Public Key has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str)); + auto res = std::mismatch(config::bls_public_key_prefix.begin(), config::bls_public_key_prefix.end(), + base58str.begin()); + FC_ASSERT(res.first == config::bls_public_key_prefix.end(), "BLS Public Key has invalid format : ${str}", ("str", base58str)); - auto data_str = base58str.substr(8); + auto data_str = base58str.substr(config::bls_public_key_prefix.size()); std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); @@ -36,7 +30,7 @@ namespace fc::crypto::blslib { std::string data_str = fc::crypto::blslib::deserialize_base58>(bytes, yield); - return std::string(config::bls_public_key_base_prefix) + "_" + std::string(config::bls_public_key_prefix) + "_" + data_str; + return std::string(config::bls_public_key_prefix) + data_str; } diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 0c474ec206..b115cff861 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -6,25 +6,19 @@ namespace fc::crypto::blslib { static bls12_381::g2 sig_parse_base58(const std::string& base58str) - { try { + { + try { - const auto pivot = base58str.find('_'); - FC_ASSERT(pivot != std::string::npos, "No delimiter in string, cannot determine data type: ${str}", ("str", base58str)); + auto data_str = base58str.substr(config::bls_signature_prefix.size()); - const auto base_prefix_str = base58str.substr(0, 3); - FC_ASSERT(config::bls_signature_base_prefix == base_prefix_str, "BLS Signature has invalid base prefix: ${str}", ("str", base58str)("base_prefix_str", base_prefix_str)); - - const auto prefix_str = base58str.substr(pivot + 1, 3); - FC_ASSERT(config::bls_signature_prefix == prefix_str, "BLS Signature has invalid prefix: ${str}", ("str", base58str)("prefix_str", prefix_str)); - - auto data_str = base58str.substr(8); + std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); - std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); + std::optional g2 = bls12_381::g2::fromCompressedBytesBE(bytes); + FC_ASSERT(g2); + return *g2; - std::optional g2 = bls12_381::g2::fromCompressedBytesBE(bytes); - FC_ASSERT(g2); - return *g2; - } FC_RETHROW_EXCEPTIONS( warn, "error parsing bls_signature", ("str", base58str ) ) } + } FC_RETHROW_EXCEPTIONS( warn, "error parsing bls_signature", ("str", base58str ) ) + } bls_signature::bls_signature(const std::string& base58str) :_sig(sig_parse_base58(base58str)) @@ -37,7 +31,7 @@ namespace fc::crypto::blslib { std::string data_str = fc::crypto::blslib::deserialize_base58>(bytes, yield); - return std::string(config::bls_signature_base_prefix) + "_" + std::string(config::bls_signature_prefix) + "_" + data_str; + return std::string(config::bls_signature_prefix) + data_str; } @@ -47,7 +41,9 @@ namespace fc::crypto::blslib { } bool operator == ( const bls_signature& p1, const bls_signature& p2) { - return p1._sig == p2._sig; + + // until `bls12_381::g2` has an `operator==`, do binary comparison + return std::memcmp(&p1._sig, &p2._sig, sizeof(p1._sig)) == 0; } } // fc::crypto::blslib diff --git a/libraries/libfc/src/crypto/bls_utils.cpp b/libraries/libfc/src/crypto/bls_utils.cpp index 0da768c3b7..93e44fc9b6 100644 --- a/libraries/libfc/src/crypto/bls_utils.cpp +++ b/libraries/libfc/src/crypto/bls_utils.cpp @@ -3,12 +3,12 @@ namespace fc::crypto::blslib { bool verify(const bls_public_key& pubkey, - const vector& message, + const std::vector& message, const bls_signature& signature) { return bls12_381::verify(pubkey._pkey, message, signature._sig); }; - bls_public_key aggregate(const vector& keys) { + bls_public_key aggregate(const std::vector& keys) { std::vector ks; ks.reserve(keys.size()); for( const auto& k : keys ) { @@ -18,7 +18,7 @@ namespace fc::crypto::blslib { return bls_public_key(agg); }; - bls_signature aggregate(const vector& signatures) { + bls_signature aggregate(const std::vector& signatures) { std::vector sigs; sigs.reserve(signatures.size()); for( const auto& s : signatures ) { @@ -29,8 +29,8 @@ namespace fc::crypto::blslib { return bls_signature{agg}; }; - bool aggregate_verify(const vector& pubkeys, - const vector>& messages, + bool aggregate_verify(const std::vector& pubkeys, + const std::vector>& messages, const bls_signature& signature) { std::vector ks; ks.reserve(pubkeys.size()); diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 449bb0ee99..be432378db 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -77,11 +77,11 @@ BOOST_AUTO_TEST_CASE(bls_sig_verif_hotstuff_types) try { bls_private_key sk = bls_private_key(seed_1); bls_public_key pk = sk.get_public_key(); - string cmt = "cm_prepare"; + std::string cmt = "cm_prepare"; uint32_t view_number = 264; - string s_view_number = to_string(view_number); - string c_s = cmt + s_view_number; + std::string s_view_number = std::to_string(view_number); + std::string c_s = cmt + s_view_number; fc::sha256 h1 = fc::sha256::hash(c_s); fc::sha256 h2 = fc::sha256::hash( std::make_pair( h1, message_3 ) ); @@ -145,8 +145,8 @@ BOOST_AUTO_TEST_CASE(bls_agg_tree_verif) try { bls_signature aggSig = aggregate({sig1, sig2}); - vector pubkeys = {pk1, pk2}; - vector> messages = {message_1, message_2}; + std::vector pubkeys = {pk1, pk2}; + std::vector> messages = {message_1, message_2}; // Verify the signature bool ok = aggregate_verify(pubkeys, messages, aggSig); From 14fc742c310277df91ca939afc452f5a2608f894 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 25 Aug 2023 19:37:58 +0000 Subject: [PATCH 074/151] Added correct prefix verification for bls signature --- libraries/libfc/src/crypto/bls_signature.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index b115cff861..f06a835ffd 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -9,6 +9,10 @@ namespace fc::crypto::blslib { { try { + auto res = std::mismatch(config::bls_signature_prefix.begin(), config::bls_signature_prefix.end(), + base58str.begin()); + FC_ASSERT(res.first == config::bls_signature_prefix.end(), "BLS Signature has invalid format : ${str}", ("str", base58str)); + auto data_str = base58str.substr(config::bls_signature_prefix.size()); std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); From e27c8279e9785cc514b5d43d3456cca866e72036 Mon Sep 17 00:00:00 2001 From: fcecin Date: Fri, 25 Aug 2023 17:16:25 -0300 Subject: [PATCH 075/151] Fixes & get finalizer info to pacemaker - Storing set_finalizer data at controller - chain_pacemaker retrievies set_finalizer data on get_finalizers() (not using it and not thread-safe yet) - Fix legacy span - Fix remove signal stub - Fix finalizer name to string description - Fix missing finalizer_set intrinsic whitelist upon feature activation --- libraries/chain/controller.cpp | 21 ++++++++++++++---- .../chain/include/eosio/chain/controller.hpp | 3 +-- .../include/eosio/chain/finalizer_set.hpp | 22 +++++++++---------- .../eosio/chain/webassembly/interface.hpp | 2 +- libraries/chain/webassembly/privileged.cpp | 10 ++++----- libraries/hotstuff/chain_pacemaker.cpp | 19 ++++++++++++++++ .../eosio/hotstuff/chain_pacemaker.hpp | 3 ++- 7 files changed, 56 insertions(+), 24 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index b0feb1c9f3..cc855a1937 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -263,6 +263,10 @@ struct controller_impl { map< account_name, map > apply_handlers; unordered_map< builtin_protocol_feature_t, std::function, enum_hash > protocol_feature_activation_handlers; + // TODO: This probably wants to be something better; + // Storing when set_finalizers() is called; retrievable via get_finalizers() (called by chain_pacemaker) + uint64_t fthreshold; + vector finalizers; void pop_block() { auto prev = fork_db.get_block( head->header.previous ); @@ -1991,7 +1995,13 @@ struct controller_impl { } void set_finalizers_impl(uint64_t fthreshold, vector finalizers) { - emit( self.notify_set_finalizers, std::tie(fthreshold, finalizers) ); + this->fthreshold = fthreshold; + this->finalizers = finalizers; + } + + void get_finalizers_impl(uint64_t& fthreshold, vector& finalizers) { + fthreshold = this->fthreshold; + finalizers = this->finalizers; } /** @@ -3318,7 +3328,11 @@ int64_t controller::set_proposed_producers( vector producers } void controller::set_finalizers( uint64_t fthreshold, vector finalizers ) { - my->set_finalizers_impl(fthreshold, finalizers); + my->set_finalizers_impl(fthreshold, std::move(finalizers)); +} + +void controller::get_finalizers( uint64_t& fthreshold, vector& finalizers ) { + my->get_finalizers_impl(fthreshold, finalizers); } const producer_authority_schedule& controller::active_producers()const { @@ -3884,8 +3898,7 @@ void controller_impl::on_activation( template<> void controller_impl::on_activation() { db.modify( db.get(), [&]( auto& ps ) { -#warning host functions to set proposers, leaders, finalizers/validators - // FIXME/TODO: host functions to set proposers, leaders, finalizers/validators + add_intrinsic_to_whitelist( ps.whitelisted_intrinsics, "set_finalizers" ); } ); } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index c75a3aa419..73e93689f5 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -309,6 +309,7 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector producers ); void set_finalizers( uint64_t fthreshold, vector finalizers ); + void get_finalizers( uint64_t& fthreshold, vector& finalizers ); bool light_validation_allowed() const; bool skip_auth_check()const; @@ -360,7 +361,6 @@ namespace eosio { namespace chain { signal new_hs_vote_message; signal new_hs_new_view_message; signal new_hs_new_block_message; - signal&>)> notify_set_finalizers; /* signal pre_apply_block; @@ -400,7 +400,6 @@ namespace eosio { namespace chain { chainbase::database& mutable_db()const; std::unique_ptr my; - }; } } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 5a6123617e..1acfa2374a 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -17,13 +17,13 @@ namespace eosio::chain { 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) + shared_finalizer_authority( const std::string& description, const uint64_t fweight, const fc::crypto::blslib::bls_public_key& public_key ) + :description(description) ,fweight(fweight) ,public_key(public_key) {} - name finalizer_name; + std::string description; uint64_t fweight; fc::crypto::blslib::bls_public_key public_key; }; @@ -46,17 +46,17 @@ namespace eosio::chain { struct finalizer_authority { - name finalizer_name; - uint64_t fweight; // weight that this finalizer's vote has for meeting fthreshold + std::string description; + 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 alloc) const { - return shared_finalizer_authority(finalizer_name, fweight, public_key); + return shared_finalizer_authority(description, fweight, public_key); } static auto from_shared( const shared_finalizer_authority& src ) { finalizer_authority result; - result.finalizer_name = src.finalizer_name; + result.description = src.description; result.fweight = src.fweight; result.public_key = src.public_key; return result; @@ -77,10 +77,10 @@ namespace eosio::chain { fc::variant get_abi_variant() const; 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 ); + 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 tie( lhs.finalizer_name, lhs.fweight, lhs.public_key ) != tie( rhs.finalizer_name, rhs.fweight, rhs.public_key ); + return tie( lhs.description, lhs.fweight, lhs.public_key ) != tie( rhs.description, rhs.fweight, rhs.public_key ); } }; @@ -138,7 +138,7 @@ namespace eosio::chain { } /// eosio::chain -FC_REFLECT( eosio::chain::finalizer_authority, (finalizer_name)(fweight)(public_key) ) +FC_REFLECT( eosio::chain::finalizer_authority, (description)(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_authority, (description)(fweight)(public_key) ) FC_REFLECT( eosio::chain::shared_finalizer_set, (version)(fthreshold)(finalizers) ) diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index 28528e33f6..24dc555250 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -180,7 +180,7 @@ namespace webassembly { * * @param packed_finalizer_set - a serialized finalizer_set object. */ - void set_finalizers(legacy_span packed_finalizer_set); + void set_finalizers(span packed_finalizer_set); /** * Retrieve the blockchain config parameters. diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index c985fed132..52f4b0d71d 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -151,7 +151,7 @@ namespace eosio { namespace chain { namespace webassembly { } } - void interface::set_finalizers(legacy_span packed_finalizer_set) { + 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"); fc::datastream ds( packed_finalizer_set.data(), packed_finalizer_set.size() ); finalizer_set finset; @@ -162,18 +162,18 @@ namespace eosio { namespace chain { namespace webassembly { EOS_ASSERT( finalizers.size() > 0, wasm_execution_error, "Finalizer set cannot be empty" ); std::set unique_finalizer_keys; - std::set unique_finalizers; +#warning REVIEW: Is checking for unique finalizer descriptions at all relevant? + std::set 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" ); 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); + unique_finalizers.insert(f.description); } - EOS_ASSERT( finalizers.size() == unique_finalizers.size(), wasm_execution_error, "Duplicate finalizer name in finalizer set" ); + 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 treshold cannot be met by finalizer weights" ); diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index f5763150e9..d9f4d06305 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -235,6 +235,25 @@ namespace eosio { namespace hotstuff { } std::vector 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 + // + uint64_t fthreshold; + vector finalizers; + _chain->get_finalizers(fthreshold, finalizers); + + // Old code: get eosio::name from the producer schedule const block_state_ptr& hbs = _chain->head_block_state(); const std::vector& pa_list = hbs->active_schedule.producers; std::vector pn_list; diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index b61015d0a6..f2451d267b 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -3,6 +3,8 @@ #include #include +#include + #include namespace eosio::chain { @@ -70,7 +72,6 @@ namespace eosio::hotstuff { uint32_t _quorum_threshold = 15; //FIXME/TODO: calculate from schedule fc::logger& _logger; - }; } // namespace eosio::hotstuff From f198385f5b3a7215fb716431a863ebdc94dfd0ae Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Fri, 25 Aug 2023 20:20:07 +0000 Subject: [PATCH 076/151] Added == operator to bls_private_key + unit test for binary constructor and base58 constructor --- .../include/fc/crypto/bls_private_key.hpp | 1 + .../libfc/include/fc/crypto/bls_public_key.hpp | 1 - libraries/libfc/src/crypto/bls_private_key.cpp | 4 ++++ libraries/libfc/src/crypto/bls_public_key.cpp | 5 ----- libraries/libfc/src/crypto/bls_signature.cpp | 5 ----- libraries/libfc/test/test_bls.cpp | 18 ++++++++++++++++++ 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 30ad4a254e..c16a7ae42a 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -37,6 +37,7 @@ namespace fc::crypto::blslib { private: std::array _sk; + friend bool operator == ( const bls_private_key& pk1, const bls_private_key& pk2); friend struct reflector; }; // bls_private_key diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index 03301cb580..4c8191af4e 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -34,7 +34,6 @@ namespace fc::crypto::blslib { bls12_381::g1 _pkey; private: - friend std::ostream& operator<< (std::ostream& s, const bls_public_key& k); friend struct reflector; friend class bls_private_key; }; // bls_public_key diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index bcce24cbf2..276ce18ef3 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -49,6 +49,10 @@ namespace fc::crypto::blslib { return std::string(config::bls_private_key_prefix) + data_str; } + bool operator == ( const bls_private_key& pk1, const bls_private_key& pk2) { + return std::memcmp(&pk1, &pk2, sizeof(pk1)) == 0; + } + } // fc::crypto::blslib namespace fc diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 34f4d869f3..7e608bddf2 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -34,11 +34,6 @@ namespace fc::crypto::blslib { } - std::ostream& operator<<(std::ostream& s, const bls_public_key& k) { - s << "bls_public_key(" << k.to_string() << ')'; - return s; - } - } // fc::crypto::blslib namespace fc diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index f06a835ffd..9111395227 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -39,11 +39,6 @@ namespace fc::crypto::blslib { } - std::ostream& operator<<(std::ostream& s, const bls_signature& k) { - s << "bls_signature(" << k.to_string() << ')'; - return s; - } - bool operator == ( const bls_signature& p1, const bls_signature& p2) { // until `bls12_381::g2` has an `operator==`, do binary comparison diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index be432378db..e60e20dfe8 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -236,4 +236,22 @@ BOOST_AUTO_TEST_CASE(bls_pub_key_sig_serialization) try { } FC_LOG_AND_RETHROW(); + +BOOST_AUTO_TEST_CASE(bls_cbinary_keys_encoding_check) try { + + bls_private_key sk = bls_private_key(seed_1); + + bool ok1 = bls_private_key(sk.to_string()) == sk; + + std::string str = sk.to_string(); + + bool ok2 = bls_private_key(str).to_string() == str; + + BOOST_CHECK_EQUAL(ok1, true); + BOOST_CHECK_EQUAL(ok2, true); + +} FC_LOG_AND_RETHROW(); + + + BOOST_AUTO_TEST_SUITE_END() From 5aaad8913d31adcafa63600babed6b734eec10ae Mon Sep 17 00:00:00 2001 From: fcecin Date: Fri, 25 Aug 2023 19:05:09 -0300 Subject: [PATCH 077/151] Placeholder fix for bls_public_key operators - Working ==, != and < operators in bls_public_key to enable testing this branch --- libraries/libfc/include/fc/crypto/bls_public_key.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index 79b83d51a7..75033bfa16 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace fc { namespace crypto { namespace blslib { @@ -60,10 +61,9 @@ namespace fc { namespace crypto { namespace blslib { friend std::ostream& operator<< (std::ostream& s, const bls_public_key& k); -#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 bool operator == ( const bls_public_key& p1, const bls_public_key& p2) { return p1._pkey.equal(p2._pkey); } + friend bool operator != ( const bls_public_key& p1, const bls_public_key& p2) { return !p1._pkey.equal(p2._pkey); } + friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2) { return bls12_381::scalar::cmp(p1._pkey.x.d, p2._pkey.x.d) < 0; } friend struct reflector; friend class bls_private_key; }; // bls_public_key From 02abeb443770234b9a8794289b2800ad0bd08eef Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sat, 26 Aug 2023 00:05:07 +0000 Subject: [PATCH 078/151] Added tests for public key encoding, use std::string for key prefixes --- .../include/fc/crypto/bls_private_key.hpp | 5 ++-- .../include/fc/crypto/bls_public_key.hpp | 6 ++--- .../libfc/include/fc/crypto/bls_signature.hpp | 2 +- .../libfc/src/crypto/bls_private_key.cpp | 4 +-- libraries/libfc/src/crypto/bls_public_key.cpp | 8 +++++- libraries/libfc/src/crypto/bls_signature.cpp | 6 ++--- libraries/libfc/test/test_bls.cpp | 26 ++++++++++++++++--- 7 files changed, 40 insertions(+), 17 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index c16a7ae42a..935e974e50 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -6,7 +6,7 @@ namespace fc::crypto::blslib { namespace config { - constexpr std::string_view bls_private_key_prefix = "PVT_BLS_"; + const std::string bls_private_key_prefix = "PVT_BLS_"; }; class bls_private_key @@ -19,10 +19,10 @@ namespace fc::crypto::blslib { explicit bls_private_key(const std::vector& seed ) { _sk = bls12_381::secret_key(seed); } + explicit bls_private_key(const std::string& base58str); bls_private_key& operator=( const bls_private_key& ) = default; - explicit bls_private_key(const std::string& base58str); std::string to_string(const yield_function_t& yield = yield_function_t()) const; bls_public_key get_public_key() const; @@ -36,7 +36,6 @@ namespace fc::crypto::blslib { private: std::array _sk; - friend bool operator == ( const bls_private_key& pk1, const bls_private_key& pk2); friend struct reflector; }; // bls_private_key diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index 4c8191af4e..b58d08ca5a 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -11,7 +11,7 @@ namespace fc::crypto::blslib { namespace config { - constexpr std::string_view bls_public_key_prefix = "PUB_BLS_"; + const std::string bls_public_key_prefix = "PUB_BLS_"; }; class bls_public_key @@ -24,16 +24,16 @@ namespace fc::crypto::blslib { bls_public_key( const bls12_381::g1& pkey ){ _pkey = pkey; } + explicit bls_public_key(const std::string& base58str); bls_public_key& operator= (const bls_public_key& ) = default; - explicit bls_public_key(const std::string& base58str); - std::string to_string(const yield_function_t& yield = yield_function_t()) const; bls12_381::g1 _pkey; private: + friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2); friend struct reflector; friend class bls_private_key; }; // bls_public_key diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index b4abe0906e..3fea33e377 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -53,4 +53,4 @@ namespace fc { FC_REFLECT(bls12_381::fp, (d)) FC_REFLECT(bls12_381::fp2, (c0)(c1)) FC_REFLECT(bls12_381::g2, (x)(y)(z)) -FC_REFLECT(crypto::blslib::bls_signature, (_sig) ) +FC_REFLECT(crypto::blslib::bls_signature, (_sig) ) \ No newline at end of file diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index 276ce18ef3..1380462d05 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -46,11 +46,11 @@ namespace fc::crypto::blslib { { std::string data_str = fc::crypto::blslib::deserialize_base58>(_sk, yield); - return std::string(config::bls_private_key_prefix) + data_str; + return config::bls_private_key_prefix + data_str; } bool operator == ( const bls_private_key& pk1, const bls_private_key& pk2) { - return std::memcmp(&pk1, &pk2, sizeof(pk1)) == 0; + return pk1._sk == pk2._sk; } } // fc::crypto::blslib diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 7e608bddf2..669bece990 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -30,10 +30,16 @@ namespace fc::crypto::blslib { std::string data_str = fc::crypto::blslib::deserialize_base58>(bytes, yield); - return std::string(config::bls_public_key_prefix) + data_str; + return config::bls_public_key_prefix + data_str; } + bool operator == ( const bls_public_key& p1, const bls_public_key& p2) { + + // until `bls12_381::g1` has an `operator==`, do binary comparison + return std::memcmp(&p1._pkey, &p2._pkey, sizeof(p1._pkey)) == 0; + } + } // fc::crypto::blslib namespace fc diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 9111395227..3939d8538f 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -40,9 +40,7 @@ namespace fc::crypto::blslib { } bool operator == ( const bls_signature& p1, const bls_signature& p2) { - - // until `bls12_381::g2` has an `operator==`, do binary comparison - return std::memcmp(&p1._sig, &p2._sig, sizeof(p1._sig)) == 0; + return p1._sig == p2._sig; } } // fc::crypto::blslib @@ -58,4 +56,4 @@ namespace fc { vo = crypto::blslib::bls_signature(var.as_string()); } -} // fc +} // fc \ No newline at end of file diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index e60e20dfe8..9e7954a566 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -237,18 +237,38 @@ BOOST_AUTO_TEST_CASE(bls_pub_key_sig_serialization) try { } FC_LOG_AND_RETHROW(); -BOOST_AUTO_TEST_CASE(bls_cbinary_keys_encoding_check) try { +BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { bls_private_key sk = bls_private_key(seed_1); bool ok1 = bls_private_key(sk.to_string()) == sk; - std::string str = sk.to_string(); + std::string priv_str = sk.to_string(); - bool ok2 = bls_private_key(str).to_string() == str; + bool ok2 = bls_private_key(priv_str).to_string() == priv_str; + + bls_public_key pk = sk.get_public_key(); + + bool ok3 = bls_public_key(pk.to_string()) == pk; + + std::string pub_str = pk.to_string(); + + bool ok4 = bls_public_key(pub_str).to_string() == pub_str; + + //bls_signature sig = sk.sign(message_1); + + //bool ok5 = bls_signature(sig.to_string()) == sig; + + //std::string sig_str = sig.to_string(); + + //bool ok6 = bls_signature(sig_str).to_string() == sig_str; BOOST_CHECK_EQUAL(ok1, true); BOOST_CHECK_EQUAL(ok2, true); + BOOST_CHECK_EQUAL(ok3, true); + BOOST_CHECK_EQUAL(ok4, true); + //BOOST_CHECK_EQUAL(ok5, true); + //BOOST_CHECK_EQUAL(ok6, true); } FC_LOG_AND_RETHROW(); From ee8eff1d980fc5494212e9841ee96a88417351db Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Fri, 25 Aug 2023 22:09:34 -0300 Subject: [PATCH 079/151] controller::get_finalizer returns finalizer info Co-authored-by: Gregory Popovitch --- libraries/chain/controller.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index cc855a1937..7908af0122 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -3331,8 +3331,8 @@ void controller::set_finalizers( uint64_t fthreshold, vectorset_finalizers_impl(fthreshold, std::move(finalizers)); } -void controller::get_finalizers( uint64_t& fthreshold, vector& finalizers ) { - my->get_finalizers_impl(fthreshold, finalizers); +std::pair> controller::get_finalizers() const { + return my->get_finalizers_impl(); } const producer_authority_schedule& controller::active_producers()const { From 1cc704b3bff3b6a4c28aba3077ccab843a8810dc Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Fri, 25 Aug 2023 22:34:25 -0300 Subject: [PATCH 080/151] Remove vector copy Co-authored-by: Gregory Popovitch --- libraries/chain/controller.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 7908af0122..cfca0bcaab 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1996,7 +1996,7 @@ struct controller_impl { void set_finalizers_impl(uint64_t fthreshold, vector finalizers) { this->fthreshold = fthreshold; - this->finalizers = finalizers; + this->finalizers = std::move(finalizers); } void get_finalizers_impl(uint64_t& fthreshold, vector& finalizers) { From 83183dda611af70d12e28b8dee36826c31b96730 Mon Sep 17 00:00:00 2001 From: fcecin Date: Sat, 26 Aug 2023 00:05:24 -0300 Subject: [PATCH 081/151] Small fixes - Tie up get_finalizer return value changes - Better operator< for bls_public_key --- libraries/chain/controller.cpp | 5 ++--- libraries/chain/include/eosio/chain/controller.hpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 4 +--- libraries/libfc/include/fc/crypto/bls_public_key.hpp | 3 +-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index cfca0bcaab..d33560c770 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1999,9 +1999,8 @@ struct controller_impl { this->finalizers = std::move(finalizers); } - void get_finalizers_impl(uint64_t& fthreshold, vector& finalizers) { - fthreshold = this->fthreshold; - finalizers = this->finalizers; + std::pair> get_finalizers_impl() { + return { fthreshold, finalizers }; } /** diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 73e93689f5..8236ba354e 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -309,7 +309,7 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector producers ); void set_finalizers( uint64_t fthreshold, vector finalizers ); - void get_finalizers( uint64_t& fthreshold, vector& finalizers ); + std::pair> get_finalizers() const; bool light_validation_allowed() const; bool skip_auth_check()const; diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index d9f4d06305..54d952622f 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -249,9 +249,7 @@ namespace eosio { namespace hotstuff { // - 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 // - uint64_t fthreshold; - vector finalizers; - _chain->get_finalizers(fthreshold, finalizers); + auto [threshold, finalizers] = _chain->get_finalizers(); // Old code: get eosio::name from the producer schedule const block_state_ptr& hbs = _chain->head_block_state(); diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index 75033bfa16..da99acf537 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -7,7 +7,6 @@ #include #include #include -#include namespace fc { namespace crypto { namespace blslib { @@ -63,7 +62,7 @@ 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) { return p1._pkey.equal(p2._pkey); } friend bool operator != ( const bls_public_key& p1, const bls_public_key& p2) { return !p1._pkey.equal(p2._pkey); } - friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2) { return bls12_381::scalar::cmp(p1._pkey.x.d, p2._pkey.x.d) < 0; } + friend bool operator < ( const bls_public_key& p1, const bls_public_key& p2) { return p1._pkey.affine().x.cmp(p2._pkey.affine().x) < 0; } friend struct reflector; friend class bls_private_key; }; // bls_public_key From c9fec694e07380c4d0b04941fc4744f60052864e Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Sat, 26 Aug 2023 08:29:58 -0300 Subject: [PATCH 082/151] Refactor finalizer_authority Co-authored-by: Gregory Popovitch --- libraries/chain/include/eosio/chain/finalizer_set.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 1acfa2374a..77cf7d9063 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -55,11 +55,7 @@ namespace eosio::chain { } static auto from_shared( const shared_finalizer_authority& src ) { - finalizer_authority result; - result.description = src.description; - result.fweight = src.fweight; - result.public_key = src.public_key; - return result; + return finalizer_authority { src.description, src.fweight, src.public_key }; } /** From 3b3f55a1c8952ed9bfd37bacb324fc84b2fb6878 Mon Sep 17 00:00:00 2001 From: Fabiana Cecin Date: Sat, 26 Aug 2023 08:31:08 -0300 Subject: [PATCH 083/151] Refactor finalizer_authority Co-authored-by: Gregory Popovitch --- libraries/chain/include/eosio/chain/finalizer_set.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 77cf7d9063..55b02965a7 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -76,7 +76,7 @@ namespace eosio::chain { 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 tie( lhs.description, lhs.fweight, lhs.public_key ) != tie( rhs.description, rhs.fweight, rhs.public_key ); + return !(lhs == rhs); } }; From 2c8720efc22fbf3c64adfe8642db889dce556e11 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Sat, 26 Aug 2023 09:37:14 -0500 Subject: [PATCH 084/151] GH-1547 Address peer review comments --- libraries/chain/include/eosio/chain/hotstuff.hpp | 4 ++-- libraries/hotstuff/qc_chain.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 629d9333a0..eca54f4ec5 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -36,11 +36,11 @@ namespace eosio::chain { quorum_met = false; } - auto get_active_finalizers() const { + boost::dynamic_bitset<> get_active_finalizers() const { assert(!active_finalizers.empty()); return boost::dynamic_bitset(active_finalizers); } - void set_active_finalizers(const auto& bs) { + void set_active_finalizers(const boost::dynamic_bitset<>& bs) { assert(!bs.empty()); boost::to_string(bs, active_finalizers); } diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 83859c57b2..bbc0fdd09d 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -237,7 +237,7 @@ namespace eosio { namespace hotstuff { fc::crypto::blslib::bls_public_key agg_key; for (boost::dynamic_bitset<>::size_type i = 0; i < finalizers.size(); i++) { - if (finalizers[i] == 1){ + if (finalizers[i]){ //adding finalizer's key to the aggregate pub key if (first) { first = false; From 22c0a44be2cb5dac416262cc73864073589387c3 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Sat, 26 Aug 2023 09:56:12 -0500 Subject: [PATCH 085/151] GH-1553 Rewrite to rm recursive implementation --- libraries/hotstuff/qc_chain.cpp | 70 ++++++++++++++------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 94d43cdb2b..ed760d6d28 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -1,6 +1,7 @@ #include #include +#include /* @@ -1054,68 +1055,57 @@ namespace eosio { namespace hotstuff { #endif } - void qc_chain::commit(const hs_proposal_message & proposal){ +void qc_chain::commit(const hs_proposal_message& initial_proposal) { + std::stack proposal_stack; + proposal_stack.push(&initial_proposal); + + while (!proposal_stack.empty()) { + const hs_proposal_message* proposal = proposal_stack.top(); + proposal_stack.pop(); fc_tlog(_logger, " === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", proposal.block_num()) - ("proposal_id", proposal.proposal_id) - ("block_id", proposal.block_id) - ("phase_counter", proposal.phase_counter) - ("parent_id", proposal.parent_id)); + ("block_num", proposal->block_num())("proposal_id", proposal->proposal_id)("block_id", proposal->block_id) + ("phase_counter", proposal->phase_counter)("parent_id", proposal->parent_id)); bool exec_height_check = false; - const hs_proposal_message *last_exec_prop = get_proposal( _b_exec ); - EOS_ASSERT( last_exec_prop != nullptr || _b_exec == NULL_PROPOSAL_ID, chain_exception, "expected hs_proposal ${id} not found", ("id", _b_exec) ); + const hs_proposal_message* last_exec_prop = get_proposal(_b_exec); + EOS_ASSERT(last_exec_prop != nullptr || _b_exec == NULL_PROPOSAL_ID, chain_exception, + "expected hs_proposal ${id} not found", ("id", _b_exec)); if (last_exec_prop != nullptr) { fc_tlog(_logger, " === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", last_exec_prop->block_num()) - ("proposal_id", last_exec_prop->proposal_id) - ("block_id", last_exec_prop->block_id) - ("phase_counter", last_exec_prop->phase_counter) - ("parent_id", last_exec_prop->parent_id)); + ("block_num", last_exec_prop->block_num())("proposal_id", last_exec_prop->proposal_id)("block_id", last_exec_prop->block_id) + ("phase_counter", last_exec_prop->phase_counter)("parent_id", last_exec_prop->parent_id)); fc_tlog(_logger, " *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", - ("proposal_id_1", last_exec_prop->block_num()) - ("phase_counter_1", last_exec_prop->phase_counter) - ("proposal_id_2", proposal.block_num()) - ("phase_counter_2", proposal.phase_counter)); + ("proposal_id_1", last_exec_prop->block_num())("phase_counter_1", last_exec_prop->phase_counter) + ("proposal_id_2", proposal->block_num())("phase_counter_2", proposal->phase_counter)); } else { fc_tlog(_logger, " === _b_exec proposal is null vs proposal ${proposal_id_2} ${phase_counter_2} ", - ("proposal_id_2", proposal.block_num()) - ("phase_counter_2", proposal.phase_counter)); + ("proposal_id_2", proposal->block_num())("phase_counter_2", proposal->phase_counter)); } - if (_b_exec == NULL_PROPOSAL_ID) + if (_b_exec == NULL_PROPOSAL_ID) { exec_height_check = true; - else - exec_height_check = last_exec_prop->get_height() < proposal.get_height(); - - if (exec_height_check){ + } else { + exec_height_check = last_exec_prop->get_height() < proposal->get_height(); + } - const hs_proposal_message *p = get_proposal( proposal.parent_id ); + if (exec_height_check) { + const hs_proposal_message* p = get_proposal(proposal->parent_id); if (p != nullptr) { - //fc_tlog(_logger, " === recursively committing" ); - commit(*p); //recursively commit all non-committed ancestor blocks sequentially first + proposal_stack.push(p); // Push the parent proposal onto the stack for processing } - //Execute commands [...] - + // Execute commands [...] fc_dlog(_logger, " === ${id} committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("block_id", proposal.block_id) - ("proposal_id", proposal.proposal_id)); - } - else { + ("id", _id)("block_num", proposal->block_num())("phase_counter", proposal->phase_counter)("block_id", proposal->block_id)("proposal_id", proposal->proposal_id)); + } else { fc_elog(_logger, " *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", - ("id", _id) - ("block_num", proposal.block_num()) - ("phase_counter", proposal.phase_counter) - ("proposal_id", proposal.proposal_id)); + ("id", _id)("block_num", proposal->block_num())("phase_counter", proposal->phase_counter)("proposal_id", proposal->proposal_id)); } } +} }} From 02841abd2a713bbbb9ce5058912423db520984dc Mon Sep 17 00:00:00 2001 From: fcecin Date: Sat, 26 Aug 2023 12:55:56 -0300 Subject: [PATCH 086/151] Misc fixes - Fix breaking libtester w/ finalizer set fwd decl - Remove finalizer_authority::get_abi_variant - Fix init fthreshold in controller - Add const to controller get_finalizer_impl() --- libraries/chain/controller.cpp | 5 +++-- .../chain/include/eosio/chain/controller.hpp | 3 +-- .../chain/include/eosio/chain/finalizer_set.hpp | 15 +-------------- libraries/chain/webassembly/privileged.cpp | 2 +- 4 files changed, 6 insertions(+), 19 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index d33560c770..cf81e2c7e2 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -265,7 +266,7 @@ struct controller_impl { // TODO: This probably wants to be something better; // Storing when set_finalizers() is called; retrievable via get_finalizers() (called by chain_pacemaker) - uint64_t fthreshold; + uint64_t fthreshold = 0; vector finalizers; void pop_block() { @@ -1999,7 +2000,7 @@ struct controller_impl { this->finalizers = std::move(finalizers); } - std::pair> get_finalizers_impl() { + std::pair> get_finalizers_impl() const { return { fthreshold, finalizers }; } diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 8236ba354e..a0f5b78d5a 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -10,8 +10,6 @@ #include #include -#include - namespace chainbase { class database; } @@ -31,6 +29,7 @@ namespace eosio { namespace chain { using hs_vote_message_ptr = std::shared_ptr; using hs_new_view_message_ptr = std::shared_ptr; using hs_new_block_message_ptr = std::shared_ptr; + struct finalizer_authority; class authorization_manager; diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 55b02965a7..5d669fd44a 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -23,6 +23,7 @@ namespace eosio::chain { ,public_key(public_key) {} +#warning FIXME: Must change std::string to shared_string. std::string description; uint64_t fweight; fc::crypto::blslib::bls_public_key public_key; @@ -58,20 +59,6 @@ namespace eosio::chain { return finalizer_authority { src.description, src.fweight, src.public_key }; } - /** - * 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; - 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 ); } diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index 52f4b0d71d..b2a471d425 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -175,7 +175,7 @@ namespace eosio { namespace chain { namespace webassembly { 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 treshold cannot be met by finalizer weights" ); + 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.fthreshold, std::move(finalizers) ); } From dd9802a3af612746fb0a4da7b05432435efe7fb9 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Sat, 26 Aug 2023 12:34:18 -0500 Subject: [PATCH 087/151] GH-1547 Create a seperate quorum_certificate_message type --- .../chain/include/eosio/chain/hotstuff.hpp | 54 ++------- .../include/eosio/hotstuff/qc_chain.hpp | 62 +++++++++- libraries/hotstuff/qc_chain.cpp | 83 ++++++------- libraries/hotstuff/test/test_hotstuff.cpp | 114 +++++++++--------- .../eosio/chain_plugin/chain_plugin.hpp | 6 +- 5 files changed, 166 insertions(+), 153 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index eca54f4ec5..f71dd37983 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -22,42 +22,10 @@ namespace eosio::chain { std::map bls_pub_keys; }; - struct quorum_certificate { - explicit quorum_certificate(uint32_t finalizer_size = 0) { - reset(NULL_PROPOSAL_ID, finalizer_size); - } - - void reset(const fc::sha256& proposal, uint32_t finalizer_size) { - proposal_id = proposal; - boost::dynamic_bitset b; - b.resize(finalizer_size); - boost::to_string(b, active_finalizers); - active_agg_sig = fc::crypto::blslib::bls_signature(); - quorum_met = false; - } - - boost::dynamic_bitset<> get_active_finalizers() const { - assert(!active_finalizers.empty()); - return boost::dynamic_bitset(active_finalizers); - } - void set_active_finalizers(const boost::dynamic_bitset<>& bs) { - assert(!bs.empty()); - boost::to_string(bs, active_finalizers); - } - const std::string& get_active_finalizers_string() const { return active_finalizers; } - - const fc::sha256& get_proposal_id() const { return proposal_id; } - const fc::crypto::blslib::bls_signature& get_active_agg_sig() const { return active_agg_sig; } - void set_active_agg_sig( const fc::crypto::blslib::bls_signature& sig) { active_agg_sig = sig; } - bool is_quorum_met() const { return quorum_met; } - void set_quorum_met() { quorum_met = true; } - - private: - friend struct fc::reflector; + struct quorum_certificate_message { fc::sha256 proposal_id = NULL_PROPOSAL_ID; std::string active_finalizers; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; - bool quorum_met = false; // not serialized across network }; struct hs_vote_message { @@ -71,7 +39,7 @@ namespace eosio::chain { block_id_type block_id = NULL_BLOCK_ID; fc::sha256 parent_id = NULL_PROPOSAL_ID; //new proposal fc::sha256 final_on_qc = NULL_PROPOSAL_ID; - quorum_certificate justify; //justification + quorum_certificate_message justify; //justification uint8_t phase_counter = 0; uint32_t block_num() const { return block_header::num_from_id(block_id); } @@ -79,16 +47,15 @@ namespace eosio::chain { }; struct hs_new_block_message { - block_id_type block_id = NULL_BLOCK_ID; //new proposal - quorum_certificate justify; //justification + block_id_type block_id = NULL_BLOCK_ID; //new proposal + quorum_certificate_message justify; //justification }; struct hs_new_view_message { - quorum_certificate high_qc; //justification + quorum_certificate_message high_qc; //justification }; struct finalizer_state { - bool chained_mode = false; fc::sha256 b_leaf = NULL_PROPOSAL_ID; fc::sha256 b_lock = NULL_PROPOSAL_ID; @@ -97,8 +64,8 @@ namespace eosio::chain { block_id_type block_exec = NULL_BLOCK_ID; block_id_type pending_proposal_block = NULL_BLOCK_ID; uint32_t v_height = 0; - eosio::chain::quorum_certificate high_qc; - eosio::chain::quorum_certificate current_qc; + eosio::chain::quorum_certificate_message high_qc; + eosio::chain::quorum_certificate_message current_qc; eosio::chain::extended_schedule schedule; map proposals; @@ -110,15 +77,10 @@ namespace eosio::chain { } }; - using hs_proposal_message_ptr = std::shared_ptr; - using hs_vote_message_ptr = std::shared_ptr; - using hs_new_view_message_ptr = std::shared_ptr; - using hs_new_block_message_ptr = std::shared_ptr; - } //eosio::chain // // @ignore quorum_met -FC_REFLECT(eosio::chain::quorum_certificate, (proposal_id)(active_finalizers)(active_agg_sig)); +FC_REFLECT(eosio::chain::quorum_certificate_message, (proposal_id)(active_finalizers)(active_agg_sig)); FC_REFLECT(eosio::chain::extended_schedule, (producer_schedule)(bls_pub_keys)); FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(parent_id)(final_on_qc)(justify)(phase_counter)); diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index cfb340de3e..63da359ba5 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -30,6 +30,60 @@ namespace eosio::hotstuff { using namespace boost::multi_index; using namespace eosio::chain; + class quorum_certificate { + public: + explicit quorum_certificate(uint32_t finalizer_size = 0) { + active_finalizers.resize(finalizer_size); + } + + explicit quorum_certificate(const quorum_certificate_message& msg) + : proposal_id(msg.proposal_id) + , active_finalizers(msg.active_finalizers) // conversion from string + , active_agg_sig(msg.active_agg_sig) { + } + + quorum_certificate_message to_msg() const { + return {.proposal_id = proposal_id, + .active_finalizers = [this](){ std::string r; boost::to_string(active_finalizers, r); return r;}(), + .active_agg_sig = active_agg_sig}; + } + + void reset(const fc::sha256& proposal, uint32_t finalizer_size) { + proposal_id = proposal; + active_finalizers.clear(); + active_finalizers.resize(finalizer_size); + active_agg_sig = fc::crypto::blslib::bls_signature(); + quorum_met = false; + } + + boost::dynamic_bitset<> get_active_finalizers() const { + assert(!active_finalizers.empty()); + return boost::dynamic_bitset(active_finalizers); + } + void set_active_finalizers(const boost::dynamic_bitset<>& bs) { + assert(!bs.empty()); + active_finalizers = bs; + } + std::string get_active_finalizers_string() const { + std::string r; + boost::to_string(active_finalizers, r); + return r; + } + + const fc::sha256& get_proposal_id() const { return proposal_id; } + const fc::crypto::blslib::bls_signature& get_active_agg_sig() const { return active_agg_sig; } + void set_active_agg_sig( const fc::crypto::blslib::bls_signature& sig) { active_agg_sig = sig; } + bool is_quorum_met() const { return quorum_met; } + void set_quorum_met() { quorum_met = true; } + + private: + friend struct fc::reflector; + fc::sha256 proposal_id = NULL_PROPOSAL_ID; + boost::dynamic_bitset<> active_finalizers; //bitset encoding, following canonical order + fc::crypto::blslib::bls_signature active_agg_sig; + bool quorum_met = false; // not serialized across network + }; + // Concurrency note: qc_chain is a single-threaded and lock-free decision engine. // All thread synchronization, if any, is external. class qc_chain { @@ -72,7 +126,7 @@ namespace eosio::hotstuff { bool evaluate_quorum(const extended_schedule& es, const boost::dynamic_bitset<>& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal // qc.quorum_met has to be updated by the caller (if it wants to) based on the return value of this method - bool is_quorum_met(const eosio::chain::quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal); //check if quorum has been met over a proposal + bool is_quorum_met(const quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal); //check if quorum has been met over a proposal hs_proposal_message new_proposal_candidate(const block_id_type& block_id, uint8_t phase_counter); //create new proposal message hs_new_block_message new_block_candidate(const block_id_type& block_id); //create new block message @@ -90,7 +144,7 @@ namespace eosio::hotstuff { bool extends(const fc::sha256& descendant, const fc::sha256& ancestor); //verify that a proposal descends from another - bool update_high_qc(const eosio::chain::quorum_certificate& high_qc); //check if update to our high qc is required + bool update_high_qc(const quorum_certificate& high_qc); //check if update to our high qc is required void leader_rotation_check(); //check if leader rotation is required @@ -131,8 +185,8 @@ namespace eosio::hotstuff { fc::sha256 _b_lock = NULL_PROPOSAL_ID; fc::sha256 _b_exec = NULL_PROPOSAL_ID; fc::sha256 _b_finality_violation = NULL_PROPOSAL_ID; - eosio::chain::quorum_certificate _high_qc; - eosio::chain::quorum_certificate _current_qc; + quorum_certificate _high_qc; + quorum_certificate _current_qc; uint32_t _v_height = 0; eosio::chain::extended_schedule _schedule; base_pacemaker* _pacemaker = nullptr; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index bbc0fdd09d..35be416d52 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -70,7 +70,7 @@ namespace eosio { namespace hotstuff { #endif } - bool qc_chain::insert_proposal(const hs_proposal_message & proposal) { + bool qc_chain::insert_proposal(const hs_proposal_message& proposal) { #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE uint64_t proposal_height = proposal.get_height(); ps_height_iterator psh_it = _proposal_stores_by_height.find( proposal_height ); @@ -103,8 +103,8 @@ namespace eosio { namespace hotstuff { fs.block_exec = _block_exec; fs.pending_proposal_block = _pending_proposal_block; fs.v_height = _v_height; - fs.high_qc = _high_qc; - fs.current_qc = _current_qc; + fs.high_qc = _high_qc.to_msg(); + fs.current_qc = _current_qc.to_msg(); fs.schedule = _schedule; #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE ps_height_iterator psh_it = _proposal_stores_by_height.begin(); @@ -159,16 +159,13 @@ namespace eosio { namespace hotstuff { std::vector qc_chain::get_qc_chain(const fc::sha256& proposal_id) { std::vector ret_arr; - const hs_proposal_message *b, *b1, *b2; - b2 = get_proposal( proposal_id ); - if (b2 != nullptr) { + if ( const hs_proposal_message* b2 = get_proposal( proposal_id ) ) { ret_arr.push_back( *b2 ); - b1 = get_proposal( b2->justify.get_proposal_id() ); - if (b1 != nullptr) { + if (const hs_proposal_message* b1 = get_proposal( b2->justify.proposal_id ) ) { ret_arr.push_back( *b1 ); - b = get_proposal( b1->justify.get_proposal_id() ); - if (b != nullptr) + if (const hs_proposal_message* b = get_proposal( b1->justify.proposal_id ) ) { ret_arr.push_back( *b ); + } } } return ret_arr; @@ -179,9 +176,9 @@ namespace eosio { namespace hotstuff { b_new.block_id = block_id; b_new.parent_id = _b_leaf; b_new.phase_counter = phase_counter; - b_new.justify = _high_qc; //or null if no _high_qc upon activation or chain launch - if (b_new.justify.get_proposal_id() != NULL_PROPOSAL_ID){ - std::vector current_qc_chain = get_qc_chain(b_new.justify.get_proposal_id()); + b_new.justify = _high_qc.to_msg(); //or null if no _high_qc upon activation or chain launch + if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ + std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); if (chain_length>=2){ auto itr = current_qc_chain.begin(); @@ -209,7 +206,7 @@ namespace eosio { namespace hotstuff { ("phase_counter", b_new.phase_counter) ("proposal_id", b_new.proposal_id) ("parent_id", b_new.parent_id) - ("justify", b_new.justify.get_proposal_id())); + ("justify", b_new.justify.proposal_id)); return b_new; } @@ -222,7 +219,7 @@ namespace eosio { namespace hotstuff { hs_new_block_message qc_chain::new_block_candidate(const block_id_type& block_id) { hs_new_block_message b; b.block_id = block_id; - b.justify = _high_qc; //or null if no _high_qc upon activation or chain launch + b.justify = _high_qc.to_msg(); //or null if no _high_qc upon activation or chain launch return b; } @@ -265,13 +262,13 @@ namespace eosio { namespace hotstuff { return ok; } - bool qc_chain::is_quorum_met(const eosio::chain::quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal) { + bool qc_chain::is_quorum_met(const quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal) { if (qc.is_quorum_met()) { return true; //skip evaluation if we've already verified quorum was met } else { - fc_tlog(_logger, " === qc : ${qc}", ("qc", qc)); + fc_tlog(_logger, " === qc : ${qc}", ("qc", qc.to_msg())); // If the caller wants to update the quorum_met flag on its "qc" object, it will have to do so // based on the return value of this method, since "qc" here is const. return evaluate_quorum(schedule, qc.get_active_finalizers(), qc.get_active_agg_sig(), proposal); @@ -280,8 +277,8 @@ namespace eosio { namespace hotstuff { qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, fc::logger& logger) - : _id(id), - _pacemaker(pacemaker), + : _pacemaker(pacemaker), + _id(id), _my_producers(std::move(my_producers)), _logger(logger) { @@ -334,11 +331,11 @@ namespace eosio { namespace hotstuff { //auto start = fc::time_point::now(); - if (proposal.justify.get_proposal_id() != NULL_PROPOSAL_ID){ + if (proposal.justify.proposal_id != NULL_PROPOSAL_ID){ - const hs_proposal_message *jp = get_proposal( proposal.justify.get_proposal_id() ); + const hs_proposal_message *jp = get_proposal( proposal.justify.proposal_id ); if (jp == nullptr) { - fc_elog(_logger, " *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.get_proposal_id())); + fc_elog(_logger, " *** ${id} proposal justification unknown : ${proposal_id}", ("id",_id)("proposal_id", proposal.justify.proposal_id)); return; //can't recognize a proposal with an unknown justification } } @@ -348,13 +345,13 @@ namespace eosio { namespace hotstuff { fc_elog(_logger, " *** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); - if (p->justify.get_proposal_id() != proposal.justify.get_proposal_id()) { + if (p->justify.proposal_id != proposal.justify.proposal_id) { fc_elog(_logger, " *** ${id} two identical proposals (${proposal_id}) have different justifications : ${justify_1} vs ${justify_2}", ("id",_id) ("proposal_id", proposal.proposal_id) - ("justify_1", p->justify.get_proposal_id()) - ("justify_2", proposal.justify.get_proposal_id())); + ("justify_1", p->justify.proposal_id) + ("justify_2", proposal.justify.proposal_id)); } @@ -403,7 +400,7 @@ namespace eosio { namespace hotstuff { ("phase_counter", proposal.phase_counter) ("proposal_id", proposal.proposal_id) ("parent_id", proposal.parent_id) - ("justify", proposal.justify.get_proposal_id())); + ("justify", proposal.justify.proposal_id)); bool success = insert_proposal( proposal ); EOS_ASSERT( success , chain_exception, "internal error: duplicate proposal insert attempt" ); // can't happen unless bad mutex somewhere; already checked for this @@ -551,7 +548,7 @@ namespace eosio { namespace hotstuff { void qc_chain::process_new_view(const hs_new_view_message & msg){ fc_tlog(_logger, " === ${id} process_new_view === ${qc}", ("qc", msg.high_qc)("id", _id)); auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); - if (!update_high_qc(msg.high_qc)) { + if (!update_high_qc(quorum_certificate{msg.high_qc})) { increment_version.cancel(); } } @@ -706,7 +703,7 @@ namespace eosio { namespace hotstuff { } // returns true on state change (caller decides update on state version - bool qc_chain::update_high_qc(const eosio::chain::quorum_certificate & high_qc){ + bool qc_chain::update_high_qc(const quorum_certificate& high_qc) { fc_tlog(_logger, " === check to update high qc ${proposal_id}", ("proposal_id", high_qc.get_proposal_id())); @@ -768,14 +765,14 @@ namespace eosio { namespace hotstuff { hs_new_view_message new_view; - new_view.high_qc = _high_qc; + new_view.high_qc = _high_qc.to_msg(); send_hs_new_view_msg(new_view); } } //safenode predicate - bool qc_chain::is_node_safe(const hs_proposal_message & proposal){ + bool qc_chain::is_node_safe(const hs_proposal_message& proposal) { //fc_tlog(_logger, " === is_node_safe ==="); @@ -786,11 +783,11 @@ namespace eosio { namespace hotstuff { fc::sha256 upcoming_commit; - if (proposal.justify.get_proposal_id() == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) final_on_qc_check = true; //if chain just launched or feature just activated else { - std::vector current_qc_chain = get_qc_chain(proposal.justify.get_proposal_id()); + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); @@ -833,13 +830,13 @@ namespace eosio { namespace hotstuff { } //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. - if (proposal.justify.get_proposal_id() == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) { + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) { liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated } else { const hs_proposal_message *b_lock = get_proposal( _b_lock ); EOS_ASSERT( b_lock != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", _b_lock) ); - const hs_proposal_message *prop_justification = get_proposal( proposal.justify.get_proposal_id() ); - EOS_ASSERT( prop_justification != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", proposal.justify.get_proposal_id()) ); + const hs_proposal_message *prop_justification = get_proposal( proposal.justify.proposal_id ); + EOS_ASSERT( prop_justification != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", proposal.justify.proposal_id) ); if (prop_justification->get_height() > b_lock->get_height()) { liveness_check = true; @@ -874,34 +871,34 @@ namespace eosio { namespace hotstuff { } //on proposal received, called from network thread - void qc_chain::on_hs_proposal_msg(const hs_proposal_message & msg){ + void qc_chain::on_hs_proposal_msg(const hs_proposal_message& msg) { process_proposal(msg); } //on vote received, called from network thread - void qc_chain::on_hs_vote_msg(const hs_vote_message & msg){ + void qc_chain::on_hs_vote_msg(const hs_vote_message& msg) { process_vote(msg); } //on new view received, called from network thread - void qc_chain::on_hs_new_view_msg(const hs_new_view_message & msg){ + void qc_chain::on_hs_new_view_msg(const hs_new_view_message& msg) { process_new_view(msg); } //on new block received, called from network thread - void qc_chain::on_hs_new_block_msg(const hs_new_block_message & msg){ + void qc_chain::on_hs_new_block_msg(const hs_new_block_message& msg) { process_new_block(msg); } - void qc_chain::update(const hs_proposal_message & proposal){ + void qc_chain::update(const hs_proposal_message& proposal) { //fc_tlog(_logger, " === update internal state ==="); //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid - if (proposal.justify.get_proposal_id() == NULL_PROPOSAL_ID){ + if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ fc_dlog(_logger, " === ${id} proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)("id", _id)); return; } - std::vector current_qc_chain = get_qc_chain(proposal.justify.get_proposal_id()); + std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); @@ -909,7 +906,7 @@ namespace eosio { namespace hotstuff { EOS_ASSERT( b_lock != nullptr || _b_lock == NULL_PROPOSAL_ID , chain_exception, "expected hs_proposal ${id} not found", ("id", _b_lock) ); //fc_tlog(_logger, " === update_high_qc : proposal.justify ==="); - update_high_qc(proposal.justify); + update_high_qc(quorum_certificate{proposal.justify}); if (chain_length<1){ fc_dlog(_logger, " === ${id} qc chain length is 0", ("id", _id)); diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index e5adbd4e1a..cba5789a39 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -120,14 +120,14 @@ class hotstuff_test_handler { finalizer_state fs; qcc.get_state(fs); const hs_proposal_message *leaf = fs.get_proposal( fs.b_leaf ); - const hs_proposal_message *qc = fs.get_proposal( fs.high_qc.get_proposal_id() ); + const hs_proposal_message *qc = fs.get_proposal( fs.high_qc.proposal_id ); const hs_proposal_message *lock = fs.get_proposal( fs.b_lock ); const hs_proposal_message *exec = fs.get_proposal( fs.b_exec ); if (leaf != nullptr) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << fs.b_leaf.str() << " block_num : " << leaf->block_num() << ", phase : " << unsigned(leaf->phase_counter) << "\n"; else std::cout << " - No b_leaf value " << "\n"; - if (qc != nullptr) std::cout << " - " << bp.to_string() << " current high_qc is : " << fs.high_qc.get_proposal_id().str() << " block_num : " << qc->block_num() << ", phase : " << unsigned(qc->phase_counter) << "\n"; + if (qc != nullptr) std::cout << " - " << bp.to_string() << " current high_qc is : " << fs.high_qc.proposal_id.str() << " block_num : " << qc->block_num() << ", phase : " << unsigned(qc->phase_counter) << "\n"; else std::cout << " - No high_qc value " << "\n"; if (lock != nullptr) std::cout << " - " << bp.to_string() << " current _b_lock is : " << fs.b_lock.str() << " block_num : " << lock->block_num() << ", phase : " << unsigned(lock->phase_counter) << "\n"; @@ -207,7 +207,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -217,7 +217,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -227,7 +227,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -237,7 +237,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -251,7 +251,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -261,7 +261,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -271,7 +271,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); @@ -281,7 +281,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); @@ -289,13 +289,13 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); //check bpb as well qcc_bpb->second->get_state(fs_bpb); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); @@ -333,7 +333,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -343,7 +343,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -355,7 +355,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -365,7 +365,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -377,7 +377,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -387,13 +387,13 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("0d77972a81cefce394736f23f8b4d97de3af5bd160376626bdd6a77de89ee324")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); //check bpb as well qcc_bpb->second->get_state(fs_bpb); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -434,7 +434,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -444,7 +444,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -454,7 +454,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -466,7 +466,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -483,7 +483,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -493,7 +493,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -503,7 +503,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -513,19 +513,19 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpa as well qcc_bpa->second->get_state(fs_bpa); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpc as well qcc_bpc->second->get_state(fs_bpc); - BOOST_CHECK_EQUAL(fs_bpc.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpc.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpc.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpc.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); @@ -566,7 +566,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -576,7 +576,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -596,7 +596,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -608,7 +608,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -634,7 +634,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, ""); qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -645,7 +645,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, ""); qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -656,7 +656,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { //ht.print_bp_state("bpa"_n, ""); qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -668,20 +668,20 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); //ht.print_bp_state("bpb"_n, ""); //check bpa as well qcc_bpb->second->get_state(fs_bpb); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); //ht.print_bp_state("bpi"_n, ""); qcc_bpi->second->get_state(fs_bpi); - BOOST_CHECK_EQUAL(fs_bpi.high_qc.get_proposal_id().str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); + BOOST_CHECK_EQUAL(fs_bpi.high_qc.proposal_id.str(), std::string("747676c95a4c866c915ab2d2171dbcaf126a4f0aeef62bf9720c138f8e03add9")); BOOST_CHECK_EQUAL(fs_bpi.b_lock.str(), std::string("f1cc5d8add3db0c0f13271815c4e08eec5e8730b0e3ba24ab7b7990981b9b338")); BOOST_CHECK_EQUAL(fs_bpi.b_exec.str(), std::string("a56ae5316e731168f5cfea5a85ffa3467b29094c2e5071019a1b89cd7fa49d98")); @@ -776,7 +776,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -790,7 +790,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -804,7 +804,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -818,7 +818,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -838,7 +838,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -852,7 +852,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); @@ -866,7 +866,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("ab04f499892ad5ebd209d54372fd5c0bda0288410a084b55c70eda40514044f3")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); @@ -880,7 +880,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { qcc_bpe->second->get_state(fs_bpe); BOOST_CHECK_EQUAL(fs_bpe.b_leaf.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); - BOOST_CHECK_EQUAL(fs_bpe.high_qc.get_proposal_id().str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); + BOOST_CHECK_EQUAL(fs_bpe.high_qc.proposal_id.str(), std::string("9eeffb58a16133517d8d2f6f90b8a3420269de3356362677055b225a44a7c151")); BOOST_CHECK_EQUAL(fs_bpe.b_lock.str(), std::string("4af7c22e5220a61ac96c35533539e65d398e9f44de4c6e11b5b0279e7a79912f")); BOOST_CHECK_EQUAL(fs_bpe.b_exec.str(), std::string("a8c84b7f9613aebf2ae34f457189d58de95a6b0a50d103a4c9e6405180d6fffb")); @@ -923,7 +923,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -933,7 +933,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -943,7 +943,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); @@ -955,7 +955,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("487e5fcbf2c515618941291ae3b6dcebb68942983d8ac3f61c4bdd9901dadbe7")); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -974,7 +974,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -984,7 +984,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); @@ -994,7 +994,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("aedf8bb1ee70bd6e743268f7fe0f8171418aa43a68bb9c6e7329ffa856896c09")); @@ -1004,19 +1004,19 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { qcc_bpb->second->get_state(fs_bpb); BOOST_CHECK_EQUAL(fs_bpb.b_leaf.str(), std::string("89f468a127dbadd81b59076067238e3e9c313782d7d83141b16d9da4f2c2b078")); - BOOST_CHECK_EQUAL(fs_bpb.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpb.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpb.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpb.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpa as well qcc_bpa->second->get_state(fs_bpa); - BOOST_CHECK_EQUAL(fs_bpa.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); //check bpc as well qcc_bpc->second->get_state(fs_bpc); - BOOST_CHECK_EQUAL(fs_bpc.high_qc.get_proposal_id().str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); + BOOST_CHECK_EQUAL(fs_bpc.high_qc.proposal_id.str(), std::string("fd77164bf3898a6a8f27ccff440d17ef6870e75c368fcc93b969066cec70939c")); BOOST_CHECK_EQUAL(fs_bpc.b_lock.str(), std::string("6462add7d157da87931c859cb689f722003a20f30c0f1408d11b872020903b85")); BOOST_CHECK_EQUAL(fs_bpc.b_exec.str(), std::string("1511035fdcbabdc5e272a3ac19356536252884ed77077cf871ae5029a7502279")); diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 1e3bffb831..173395dd38 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -839,7 +839,7 @@ class read_only : public api_base { chain::block_id_type block_id = chain::NULL_BLOCK_ID; fc::sha256 parent_id = chain::NULL_PROPOSAL_ID; fc::sha256 final_on_qc = chain::NULL_PROPOSAL_ID; - chain::quorum_certificate justify; + chain::quorum_certificate_message justify; uint8_t phase_counter = 0; uint32_t block_height = 0; uint64_t view_number = 0; @@ -866,8 +866,8 @@ class read_only : public api_base { chain::block_id_type block_exec = chain::NULL_BLOCK_ID; chain::block_id_type pending_proposal_block = chain::NULL_BLOCK_ID; uint32_t v_height = 0; - chain::quorum_certificate high_qc; - chain::quorum_certificate current_qc; + chain::quorum_certificate_message high_qc; + chain::quorum_certificate_message current_qc; chain::extended_schedule schedule; vector proposals; }; From 33ac7005a8c6c578114a596400974642ad2df9f7 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Sat, 26 Aug 2023 13:11:44 -0500 Subject: [PATCH 088/151] GH-1545 Remove NULL_BLOCK_ID and NULL_PROPOSAL_ID and use empty() instead --- .../chain/include/eosio/chain/hotstuff.hpp | 29 +++++------ .../include/eosio/hotstuff/qc_chain.hpp | 14 ++--- libraries/hotstuff/qc_chain.cpp | 52 +++++++++---------- .../eosio/chain_plugin/chain_plugin.hpp | 20 +++---- 4 files changed, 55 insertions(+), 60 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index f71dd37983..9efac815fc 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -10,9 +10,6 @@ namespace eosio::chain { - const block_id_type NULL_BLOCK_ID = block_id_type("00"); - const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - inline uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) { return (uint64_t{block_height} << 32) | phase_counter; } @@ -23,22 +20,22 @@ namespace eosio::chain { }; struct quorum_certificate_message { - fc::sha256 proposal_id = NULL_PROPOSAL_ID; + fc::sha256 proposal_id; std::string active_finalizers; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; }; struct hs_vote_message { - fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal + fc::sha256 proposal_id; //vote on proposal name finalizer; fc::crypto::blslib::bls_signature sig; }; struct hs_proposal_message { - fc::sha256 proposal_id = NULL_PROPOSAL_ID; //vote on proposal - block_id_type block_id = NULL_BLOCK_ID; - fc::sha256 parent_id = NULL_PROPOSAL_ID; //new proposal - fc::sha256 final_on_qc = NULL_PROPOSAL_ID; + fc::sha256 proposal_id; //vote on proposal + block_id_type block_id; + fc::sha256 parent_id; //new proposal + fc::sha256 final_on_qc; quorum_certificate_message justify; //justification uint8_t phase_counter = 0; @@ -47,7 +44,7 @@ namespace eosio::chain { }; struct hs_new_block_message { - block_id_type block_id = NULL_BLOCK_ID; //new proposal + block_id_type block_id; //new proposal quorum_certificate_message justify; //justification }; @@ -57,12 +54,12 @@ namespace eosio::chain { struct finalizer_state { bool chained_mode = false; - fc::sha256 b_leaf = NULL_PROPOSAL_ID; - fc::sha256 b_lock = NULL_PROPOSAL_ID; - fc::sha256 b_exec = NULL_PROPOSAL_ID; - fc::sha256 b_finality_violation = NULL_PROPOSAL_ID; - block_id_type block_exec = NULL_BLOCK_ID; - block_id_type pending_proposal_block = NULL_BLOCK_ID; + fc::sha256 b_leaf; + fc::sha256 b_lock; + fc::sha256 b_exec; + fc::sha256 b_finality_violation; + block_id_type block_exec; + block_id_type pending_proposal_block; uint32_t v_height = 0; eosio::chain::quorum_certificate_message high_qc; eosio::chain::quorum_certificate_message current_qc; diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 63da359ba5..4d446f9eb7 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -78,7 +78,7 @@ namespace eosio::hotstuff { private: friend struct fc::reflector; - fc::sha256 proposal_id = NULL_PROPOSAL_ID; + fc::sha256 proposal_id; boost::dynamic_bitset<> active_finalizers; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; bool quorum_met = false; // not serialized across network @@ -179,12 +179,12 @@ namespace eosio::hotstuff { }; bool _chained_mode = false; - block_id_type _block_exec = NULL_BLOCK_ID; - block_id_type _pending_proposal_block = NULL_BLOCK_ID; - fc::sha256 _b_leaf = NULL_PROPOSAL_ID; - fc::sha256 _b_lock = NULL_PROPOSAL_ID; - fc::sha256 _b_exec = NULL_PROPOSAL_ID; - fc::sha256 _b_finality_violation = NULL_PROPOSAL_ID; + block_id_type _block_exec; + block_id_type _pending_proposal_block; + fc::sha256 _b_leaf; + fc::sha256 _b_lock; + fc::sha256 _b_exec; + fc::sha256 _b_finality_violation; quorum_certificate _high_qc; quorum_certificate _current_qc; uint32_t _v_height = 0; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 35be416d52..b16a9d9d55 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -177,7 +177,7 @@ namespace eosio { namespace hotstuff { b_new.parent_id = _b_leaf; b_new.phase_counter = phase_counter; b_new.justify = _high_qc.to_msg(); //or null if no _high_qc upon activation or chain launch - if (b_new.justify.proposal_id != NULL_PROPOSAL_ID){ + if (!b_new.justify.proposal_id.empty()) { std::vector current_qc_chain = get_qc_chain(b_new.justify.proposal_id); size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); if (chain_length>=2){ @@ -278,12 +278,12 @@ namespace eosio { namespace hotstuff { qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, fc::logger& logger) : _pacemaker(pacemaker), - _id(id), _my_producers(std::move(my_producers)), + _id(id), _logger(logger) { - _high_qc.reset(NULL_PROPOSAL_ID, 21); // TODO: use active schedule size - _current_qc.reset(NULL_PROPOSAL_ID, 21); // TODO: use active schedule size + _high_qc.reset({}, 21); // TODO: use active schedule size + _current_qc.reset({}, 21); // TODO: use active schedule size fc_dlog(_logger, " === ${id} qc chain initialized ${my_producers}", ("my_producers", my_producers)("id", _id)); } @@ -331,7 +331,7 @@ namespace eosio { namespace hotstuff { //auto start = fc::time_point::now(); - if (proposal.justify.proposal_id != NULL_PROPOSAL_ID){ + if (!proposal.justify.proposal_id.empty()) { const hs_proposal_message *jp = get_proposal( proposal.justify.proposal_id ); if (jp == nullptr) { @@ -525,14 +525,14 @@ namespace eosio { namespace hotstuff { fc_tlog(_logger, " === ${id} phase increment on proposal ${proposal_id}", ("proposal_id", vote.proposal_id)("id", _id)); hs_proposal_message proposal_candidate; - if (_pending_proposal_block == NULL_BLOCK_ID) + if (_pending_proposal_block.empty()) proposal_candidate = new_proposal_candidate( p->block_id, p->phase_counter + 1 ); else proposal_candidate = new_proposal_candidate( _pending_proposal_block, 0 ); reset_qc(proposal_candidate.proposal_id); fc_tlog(_logger, " === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); - _pending_proposal_block = NULL_BLOCK_ID; + _pending_proposal_block = block_id_type{}; _b_leaf = proposal_candidate.proposal_id; send_hs_proposal_msg(proposal_candidate); @@ -578,7 +578,7 @@ namespace eosio { namespace hotstuff { auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); - if (_current_qc.get_proposal_id() != NULL_PROPOSAL_ID && _current_qc.is_quorum_met() == false) { + if (!_current_qc.get_proposal_id().empty() && !_current_qc.is_quorum_met()) { fc_tlog(_logger, " === ${id} pending proposal found ${proposal_id} : quorum met ${quorum_met}", ("id", _id) @@ -600,7 +600,7 @@ namespace eosio { namespace hotstuff { fc_tlog(_logger, " === ${id} setting _pending_proposal_block to null (process_new_block)", ("id", _id)); - _pending_proposal_block = NULL_BLOCK_ID; + _pending_proposal_block = block_id_type{}; _b_leaf = proposal_candidate.proposal_id; send_hs_proposal_msg(proposal_candidate); @@ -709,8 +709,7 @@ namespace eosio { namespace hotstuff { // if new high QC is higher than current, update to new - if (_high_qc.get_proposal_id() == NULL_PROPOSAL_ID){ - + if (_high_qc.get_proposal_id().empty()) { _high_qc = high_qc; _b_leaf = _high_qc.get_proposal_id(); @@ -757,11 +756,11 @@ namespace eosio { namespace hotstuff { //leader changed, we send our new_view message - reset_qc(NULL_PROPOSAL_ID); + reset_qc({}); fc_tlog(_logger, " === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); - _pending_proposal_block = NULL_BLOCK_ID; + _pending_proposal_block = block_id_type{}; hs_new_view_message new_view; @@ -783,9 +782,9 @@ namespace eosio { namespace hotstuff { fc::sha256 upcoming_commit; - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) + if (proposal.justify.proposal_id.empty() && _b_lock.empty()) { final_on_qc_check = true; //if chain just launched or feature just activated - else { + } else { std::vector current_qc_chain = get_qc_chain(proposal.justify.proposal_id); @@ -822,7 +821,7 @@ namespace eosio { namespace hotstuff { monotony_check = true; } - if (_b_lock != NULL_PROPOSAL_ID){ + if (!_b_lock.empty()) { //Safety check : check if this proposal extends the chain I'm locked on if (extends(proposal.proposal_id, _b_lock)) { @@ -830,7 +829,7 @@ namespace eosio { namespace hotstuff { } //Liveness check : check if the height of this proposal's justification is higher than the height of the proposal I'm locked on. This allows restoration of liveness if a replica is locked on a stale block. - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID && _b_lock == NULL_PROPOSAL_ID) { + if (proposal.justify.proposal_id.empty() && _b_lock.empty()) { liveness_check = true; //if there is no justification on the proposal and I am not locked on anything, means the chain just launched or feature just activated } else { const hs_proposal_message *b_lock = get_proposal( _b_lock ); @@ -893,7 +892,7 @@ namespace eosio { namespace hotstuff { void qc_chain::update(const hs_proposal_message& proposal) { //fc_tlog(_logger, " === update internal state ==="); //if proposal has no justification, means we either just activated the feature or launched the chain, or the proposal is invalid - if (proposal.justify.proposal_id == NULL_PROPOSAL_ID){ + if (proposal.justify.proposal_id.empty()) { fc_dlog(_logger, " === ${id} proposal has no justification ${proposal_id}", ("proposal_id", proposal.proposal_id)("id", _id)); return; } @@ -903,7 +902,7 @@ namespace eosio { namespace hotstuff { size_t chain_length = std::distance(current_qc_chain.begin(), current_qc_chain.end()); const hs_proposal_message *b_lock = get_proposal( _b_lock ); - EOS_ASSERT( b_lock != nullptr || _b_lock == NULL_PROPOSAL_ID , chain_exception, "expected hs_proposal ${id} not found", ("id", _b_lock) ); + EOS_ASSERT( b_lock != nullptr || _b_lock.empty(), chain_exception, "expected hs_proposal ${id} not found", ("id", _b_lock) ); //fc_tlog(_logger, " === update_high_qc : proposal.justify ==="); update_high_qc(quorum_certificate{proposal.justify}); @@ -939,8 +938,7 @@ namespace eosio { namespace hotstuff { ("b_lock_phase", b_lock->phase_counter)); } - if (_b_lock == NULL_PROPOSAL_ID || b_1.get_height() > b_lock->get_height()){ - + if (_b_lock.empty() || b_1.get_height() > b_lock->get_height()) { fc_tlog(_logger, "setting _b_lock to ${proposal_id}", ("proposal_id",b_1.proposal_id )); _b_lock = b_1.proposal_id; //commit phase on b1 @@ -965,7 +963,7 @@ namespace eosio { namespace hotstuff { //direct parent relationship verification if (b_2.parent_id == b_1.proposal_id && b_1.parent_id == b.proposal_id){ - if (_b_exec!= NULL_PROPOSAL_ID){ + if (!_b_exec.empty()) { const hs_proposal_message *b_exec = get_proposal( _b_exec ); EOS_ASSERT( b_exec != nullptr , chain_exception, "expected hs_proposal ${id} not found", ("id", _b_exec) ); @@ -1056,7 +1054,7 @@ namespace eosio { namespace hotstuff { bool exec_height_check = false; const hs_proposal_message *last_exec_prop = get_proposal( _b_exec ); - EOS_ASSERT( last_exec_prop != nullptr || _b_exec == NULL_PROPOSAL_ID, chain_exception, "expected hs_proposal ${id} not found", ("id", _b_exec) ); + EOS_ASSERT( last_exec_prop != nullptr || _b_exec.empty(), chain_exception, "expected hs_proposal ${id} not found", ("id", _b_exec) ); if (last_exec_prop != nullptr) { fc_tlog(_logger, " === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", @@ -1077,13 +1075,13 @@ namespace eosio { namespace hotstuff { ("phase_counter_2", proposal.phase_counter)); } - if (_b_exec == NULL_PROPOSAL_ID) + if (_b_exec.empty()) { exec_height_check = true; - else + } else { exec_height_check = last_exec_prop->get_height() < proposal.get_height(); + } - if (exec_height_check){ - + if (exec_height_check) { const hs_proposal_message *p = get_proposal( proposal.parent_id ); if (p != nullptr) { //fc_tlog(_logger, " === recursively committing" ); diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 173395dd38..5f5deee10a 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -835,10 +835,10 @@ class read_only : public api_base { get_consensus_parameters_results get_consensus_parameters(const get_consensus_parameters_params&, const fc::time_point& deadline) const; struct hs_complete_proposal_message { - fc::sha256 proposal_id = chain::NULL_PROPOSAL_ID; - chain::block_id_type block_id = chain::NULL_BLOCK_ID; - fc::sha256 parent_id = chain::NULL_PROPOSAL_ID; - fc::sha256 final_on_qc = chain::NULL_PROPOSAL_ID; + fc::sha256 proposal_id; + chain::block_id_type block_id; + fc::sha256 parent_id; + fc::sha256 final_on_qc; chain::quorum_certificate_message justify; uint8_t phase_counter = 0; uint32_t block_height = 0; @@ -859,12 +859,12 @@ class read_only : public api_base { using get_finalizer_state_params = empty; struct get_finalizer_state_results { bool chained_mode = false; - fc::sha256 b_leaf = chain::NULL_PROPOSAL_ID; - fc::sha256 b_lock = chain::NULL_PROPOSAL_ID; - fc::sha256 b_exec = chain::NULL_PROPOSAL_ID; - fc::sha256 b_finality_violation = chain::NULL_PROPOSAL_ID; - chain::block_id_type block_exec = chain::NULL_BLOCK_ID; - chain::block_id_type pending_proposal_block = chain::NULL_BLOCK_ID; + fc::sha256 b_leaf; + fc::sha256 b_lock; + fc::sha256 b_exec; + fc::sha256 b_finality_violation; + chain::block_id_type block_exec; + chain::block_id_type pending_proposal_block; uint32_t v_height = 0; chain::quorum_certificate_message high_qc; chain::quorum_certificate_message current_qc; From dd18c2f6e03e767dd5dc2b311b598a44f8a3c0fd Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Sat, 26 Aug 2023 13:41:52 -0500 Subject: [PATCH 089/151] GH-1545 Prefer {} to block_id_type{} --- libraries/hotstuff/qc_chain.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index b16a9d9d55..86eb7dd1cd 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -532,7 +532,7 @@ namespace eosio { namespace hotstuff { reset_qc(proposal_candidate.proposal_id); fc_tlog(_logger, " === ${id} setting _pending_proposal_block to null (process_vote)", ("id", _id)); - _pending_proposal_block = block_id_type{}; + _pending_proposal_block = {}; _b_leaf = proposal_candidate.proposal_id; send_hs_proposal_msg(proposal_candidate); @@ -600,7 +600,7 @@ namespace eosio { namespace hotstuff { fc_tlog(_logger, " === ${id} setting _pending_proposal_block to null (process_new_block)", ("id", _id)); - _pending_proposal_block = block_id_type{}; + _pending_proposal_block = {}; _b_leaf = proposal_candidate.proposal_id; send_hs_proposal_msg(proposal_candidate); @@ -760,7 +760,7 @@ namespace eosio { namespace hotstuff { fc_tlog(_logger, " === ${id} setting _pending_proposal_block to null (leader_rotation_check)", ("id", _id)); - _pending_proposal_block = block_id_type{}; + _pending_proposal_block = {}; hs_new_view_message new_view; From 86c4305ffc4aa618f141b085b0602773ed380a34 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Sat, 26 Aug 2023 14:43:05 -0500 Subject: [PATCH 090/151] GH-1547 Minor cleanup --- .../hotstuff/include/eosio/hotstuff/qc_chain.hpp | 11 +++++------ libraries/hotstuff/qc_chain.cpp | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 63da359ba5..7c759ea044 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -32,7 +32,7 @@ namespace eosio::hotstuff { class quorum_certificate { public: - explicit quorum_certificate(uint32_t finalizer_size = 0) { + explicit quorum_certificate(size_t finalizer_size = 0) { active_finalizers.resize(finalizer_size); } @@ -48,17 +48,16 @@ namespace eosio::hotstuff { .active_agg_sig = active_agg_sig}; } - void reset(const fc::sha256& proposal, uint32_t finalizer_size) { + void reset(const fc::sha256& proposal, size_t finalizer_size) { proposal_id = proposal; - active_finalizers.clear(); - active_finalizers.resize(finalizer_size); + active_finalizers = boost::dynamic_bitset<>{finalizer_size}; active_agg_sig = fc::crypto::blslib::bls_signature(); quorum_met = false; } - boost::dynamic_bitset<> get_active_finalizers() const { + const boost::dynamic_bitset<>& get_active_finalizers() const { assert(!active_finalizers.empty()); - return boost::dynamic_bitset(active_finalizers); + return active_finalizers; } void set_active_finalizers(const boost::dynamic_bitset<>& bs) { assert(!bs.empty()); diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 35be416d52..afd156f8e9 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -225,7 +225,6 @@ namespace eosio { namespace hotstuff { bool qc_chain::evaluate_quorum(const extended_schedule& es, const boost::dynamic_bitset<>& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal) { - bool first = true; if (positive_bits_count(finalizers) < _pacemaker->get_quorum_threshold()){ return false; @@ -233,7 +232,8 @@ namespace eosio { namespace hotstuff { fc::crypto::blslib::bls_public_key agg_key; - for (boost::dynamic_bitset<>::size_type i = 0; i < finalizers.size(); i++) { + bool first = true; + for (boost::dynamic_bitset<>::size_type i = 0; i < finalizers.size(); ++i) { if (finalizers[i]){ //adding finalizer's key to the aggregate pub key if (first) { @@ -493,7 +493,7 @@ namespace eosio { namespace hotstuff { auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); - boost::dynamic_bitset finalizer_set = _current_qc.get_active_finalizers(); + const boost::dynamic_bitset<>& finalizer_set = _current_qc.get_active_finalizers(); if (finalizer_set.any()) _current_qc.set_active_agg_sig(fc::crypto::blslib::aggregate({_current_qc.get_active_agg_sig(), vote.sig })); else From 8966a2913d76cb91dacf04bb608e690e89a676eb Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sun, 27 Aug 2023 16:10:51 +0000 Subject: [PATCH 091/151] Expanded bls unit tests to include additional format + checksum tests, minor style corrections --- .../include/fc/crypto/bls_private_key.hpp | 4 -- .../include/fc/crypto/bls_public_key.hpp | 10 +-- .../libfc/include/fc/crypto/bls_signature.hpp | 16 +---- libraries/libfc/libraries/bls12-381 | 2 +- libraries/libfc/src/crypto/bls_public_key.cpp | 4 +- libraries/libfc/test/test_bls.cpp | 71 ++++++++++++++++--- 6 files changed, 68 insertions(+), 39 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index 935e974e50..1893a37ebc 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -30,10 +30,6 @@ namespace fc::crypto::blslib { static bls_private_key generate(); - static bls_private_key regenerate( std::vector seed ) { - return bls_private_key(std::move(seed)); - } - private: std::array _sk; friend bool operator == ( const bls_private_key& pk1, const bls_private_key& pk2); diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index b58d08ca5a..2a2e17c77d 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -21,21 +21,15 @@ namespace fc::crypto::blslib { bls_public_key() = default; bls_public_key( bls_public_key&& ) = default; bls_public_key( const bls_public_key& ) = default; - bls_public_key( const bls12_381::g1& pkey ){ - _pkey = pkey; - } + explicit bls_public_key( const bls12_381::g1& pkey ){_pkey = pkey;} explicit bls_public_key(const std::string& base58str); bls_public_key& operator= (const bls_public_key& ) = default; - std::string to_string(const yield_function_t& yield = yield_function_t()) const; + friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2); bls12_381::g1 _pkey; - private: - friend bool operator == ( const bls_public_key& p1, const bls_public_key& p2); - friend struct reflector; - friend class bls_private_key; }; // bls_public_key } // fc::crypto::blslib diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index 3fea33e377..17b84bbe53 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -21,25 +21,15 @@ namespace fc::crypto::blslib { bls_signature() = default; bls_signature( bls_signature&& ) = default; bls_signature( const bls_signature& ) = default; - bls_signature( const bls12_381::g2& sig ){ - _sig = sig; - } + explicit bls_signature( const bls12_381::g2& sig ){_sig = sig;} + explicit bls_signature(const std::string& base58str); bls_signature& operator= (const bls_signature& ) = default; - - - explicit bls_signature(const std::string& base58str); std::string to_string(const yield_function_t& yield = yield_function_t()) const; - + friend bool operator == ( const bls_signature& p1, const bls_signature& p2); bls12_381::g2 _sig; - private: - - friend bool operator == ( const bls_signature& p1, const bls_signature& p2); - friend struct reflector; - friend class bls_private_key; - friend class bls_public_key; }; // bls_signature } // fc::crypto::blslib diff --git a/libraries/libfc/libraries/bls12-381 b/libraries/libfc/libraries/bls12-381 index a24734c86c..764b944029 160000 --- a/libraries/libfc/libraries/bls12-381 +++ b/libraries/libfc/libraries/bls12-381 @@ -1 +1 @@ -Subproject commit a24734c86cb61aa4e498181203d1fe054d9e99a0 +Subproject commit 764b944029687383c016a65a6667830a7eff2ee5 diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 669bece990..97c7c2b1c0 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -35,9 +35,7 @@ namespace fc::crypto::blslib { } bool operator == ( const bls_public_key& p1, const bls_public_key& p2) { - - // until `bls12_381::g1` has an `operator==`, do binary comparison - return std::memcmp(&p1._pkey, &p2._pkey, sizeof(p1._pkey)) == 0; + return p1._pkey == p2._pkey; } } // fc::crypto::blslib diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 9e7954a566..d1700f1c86 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -255,23 +255,74 @@ BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { bool ok4 = bls_public_key(pub_str).to_string() == pub_str; - //bls_signature sig = sk.sign(message_1); + bls_signature sig = sk.sign(message_1); - //bool ok5 = bls_signature(sig.to_string()) == sig; + bool ok5 = bls_signature(sig.to_string()) == sig; - //std::string sig_str = sig.to_string(); + std::string sig_str = sig.to_string(); - //bool ok6 = bls_signature(sig_str).to_string() == sig_str; + bool ok6 = bls_signature(sig_str).to_string() == sig_str; - BOOST_CHECK_EQUAL(ok1, true); - BOOST_CHECK_EQUAL(ok2, true); - BOOST_CHECK_EQUAL(ok3, true); - BOOST_CHECK_EQUAL(ok4, true); - //BOOST_CHECK_EQUAL(ok5, true); - //BOOST_CHECK_EQUAL(ok6, true); + bool ok7 = verify(pk, message_1, bls_signature(sig.to_string())); + bool ok8 = verify(pk, message_1, sig); + + BOOST_CHECK_EQUAL(ok1, true); //succeeds + BOOST_CHECK_EQUAL(ok2, true); //succeeds + BOOST_CHECK_EQUAL(ok3, true); //succeeds + BOOST_CHECK_EQUAL(ok4, true); //succeeds + //BOOST_CHECK_EQUAL(ok5, true); //fails + BOOST_CHECK_EQUAL(ok6, true); //succeeds + BOOST_CHECK_EQUAL(ok7, true); //succeeds + BOOST_CHECK_EQUAL(ok8, true); //succeeds } FC_LOG_AND_RETHROW(); +BOOST_AUTO_TEST_CASE(bls_prefix_encoding_check) try { + + //test no_throw for correctly encoded keys + BOOST_CHECK_NO_THROW(bls_private_key("PVT_BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG")); + BOOST_CHECK_NO_THROW(bls_public_key("PUB_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu")); + BOOST_CHECK_NO_THROW(bls_signature("SIG_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o")); + + //test no pivot delimiter + BOOST_CHECK_THROW(bls_private_key("PVTBLSM6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUBBLSZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIGBLS7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + + //test first prefix validation + BOOST_CHECK_THROW(bls_private_key("XYZ_BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("XYZ_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("XYZ_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + + //test second prefix validation + BOOST_CHECK_THROW(bls_private_key("PVT_XYZ_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_XYZ_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_XYZ_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + + //test missing prefix + BOOST_CHECK_THROW(bls_private_key("M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + + //test incomplete prefix + BOOST_CHECK_THROW(bls_private_key("PVT_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("PUB_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + + //test invalid data / invalid checksum + BOOST_CHECK_THROW(bls_private_key("PVT_BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcH"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsv"), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("PUB_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3p"), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("PVT_BLS_N6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_BLS_ACYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("PUB_BLS_6dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("PVT_BLS_M6m7EUvzEbQErhkKUrsA96VGqdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtE3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("PUB_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHug1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); +} FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_SUITE_END() From a0650f46dc0cbcd629fee7fb5f3c14f7257fbeec Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sun, 27 Aug 2023 16:36:59 +0000 Subject: [PATCH 092/151] Updated bls_public_key and bls_signature == operator to use the correct equivalence test --- libraries/libfc/src/crypto/bls_public_key.cpp | 2 +- libraries/libfc/src/crypto/bls_signature.cpp | 4 +++- libraries/libfc/test/test_bls.cpp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 97c7c2b1c0..9da57e4f7a 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -35,7 +35,7 @@ namespace fc::crypto::blslib { } bool operator == ( const bls_public_key& p1, const bls_public_key& p2) { - return p1._pkey == p2._pkey; + return p1._pkey.equal(p2._pkey); } } // fc::crypto::blslib diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 3939d8538f..c07d6cc385 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -40,7 +40,9 @@ namespace fc::crypto::blslib { } bool operator == ( const bls_signature& p1, const bls_signature& p2) { - return p1._sig == p2._sig; + + return p1._sig.equal(p2._sig); + } } // fc::crypto::blslib diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index d1700f1c86..9aa9c27f08 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -270,7 +270,7 @@ BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { BOOST_CHECK_EQUAL(ok2, true); //succeeds BOOST_CHECK_EQUAL(ok3, true); //succeeds BOOST_CHECK_EQUAL(ok4, true); //succeeds - //BOOST_CHECK_EQUAL(ok5, true); //fails + BOOST_CHECK_EQUAL(ok5, true); //fails BOOST_CHECK_EQUAL(ok6, true); //succeeds BOOST_CHECK_EQUAL(ok7, true); //succeeds BOOST_CHECK_EQUAL(ok8, true); //succeeds From d169dee288de427441dfdb3d55bdb5492ea47ca6 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sun, 27 Aug 2023 16:38:29 +0000 Subject: [PATCH 093/151] Updated bls_public_key and bls_signature == operator to use the correct equivalence test --- libraries/libfc/src/crypto/bls_signature.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index c07d6cc385..6d2fb6eebf 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -40,9 +40,7 @@ namespace fc::crypto::blslib { } bool operator == ( const bls_signature& p1, const bls_signature& p2) { - return p1._sig.equal(p2._sig); - } } // fc::crypto::blslib From 1a05a40c2a49e17d42263db05ad0e2ea4b203a56 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sun, 27 Aug 2023 10:39:42 -0600 Subject: [PATCH 094/151] Update libraries/libfc/src/crypto/bls_signature.cpp Co-authored-by: Gregory Popovitch --- libraries/libfc/src/crypto/bls_signature.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 6d2fb6eebf..cb9df7298c 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -35,7 +35,7 @@ namespace fc::crypto::blslib { std::string data_str = fc::crypto::blslib::deserialize_base58>(bytes, yield); - return std::string(config::bls_signature_prefix) + data_str; + return config::bls_signature_prefix + data_str; } From 98e1ae8a3a620314c252ea1713c3b8e3b3936b4b Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sun, 27 Aug 2023 10:40:43 -0600 Subject: [PATCH 095/151] Update libraries/libfc/include/fc/crypto/bls_signature.hpp Co-authored-by: Gregory Popovitch --- libraries/libfc/include/fc/crypto/bls_signature.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index 17b84bbe53..38111086a2 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -11,7 +11,7 @@ namespace fc::crypto::blslib { namespace config { - constexpr std::string_view bls_signature_prefix = "SIG_BLS_"; + constexpr std::string bls_signature_prefix = "SIG_BLS_"; }; class bls_signature From 22aac3bce16576b78a4e5ebe33e3bab698514cc3 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sun, 27 Aug 2023 17:04:50 +0000 Subject: [PATCH 096/151] Replace constexpr with const keyword for bls_signature_prefix declaration --- libraries/libfc/include/fc/crypto/bls_signature.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index 38111086a2..ef2b80b725 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -11,7 +11,7 @@ namespace fc::crypto::blslib { namespace config { - constexpr std::string bls_signature_prefix = "SIG_BLS_"; + const std::string bls_signature_prefix = "SIG_BLS_"; }; class bls_signature From d58870451189419e36c3a2883fa2e30c8543ed6f Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 08:16:39 -0500 Subject: [PATCH 097/151] GH-1547 Use set instead of flip as this is indicating the specified finalizer --- libraries/hotstuff/qc_chain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index afd156f8e9..b0530e082c 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -138,7 +138,7 @@ namespace eosio { namespace hotstuff { vector finalizers = _pacemaker->get_finalizers(); for (size_t i = 0; i < finalizers.size();i++) { if (finalizers[i] == finalizer) { - b.flip(i); + b.set(i); fc_tlog(_logger, " === finalizer found ${finalizer} new value : ${value}", ("finalizer", finalizer)("value", [&](){ std::string r; boost::to_string(b, r); return r; }())); From 863033f363ba940ad9655d80ace2e02f93c11be1 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 08:50:37 -0500 Subject: [PATCH 098/151] GH-1547 Use std::vector for quorum_certificate_message active_finalizers --- .../chain/include/eosio/chain/hotstuff.hpp | 4 +++- .../include/eosio/hotstuff/qc_chain.hpp | 24 ++++++++++++------- libraries/hotstuff/qc_chain.cpp | 12 +++++----- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index f71dd37983..4b119fca70 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -13,6 +13,8 @@ namespace eosio::chain { const block_id_type NULL_BLOCK_ID = block_id_type("00"); const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); + using hs_dynamic_bitset = boost::dynamic_bitset; + inline uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) { return (uint64_t{block_height} << 32) | phase_counter; } @@ -24,7 +26,7 @@ namespace eosio::chain { struct quorum_certificate_message { fc::sha256 proposal_id = NULL_PROPOSAL_ID; - std::string active_finalizers; //bitset encoding, following canonical order + std::vector active_finalizers; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; }; diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 7c759ea044..001a3c03a4 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -38,28 +38,34 @@ namespace eosio::hotstuff { explicit quorum_certificate(const quorum_certificate_message& msg) : proposal_id(msg.proposal_id) - , active_finalizers(msg.active_finalizers) // conversion from string + , active_finalizers() , active_agg_sig(msg.active_agg_sig) { + active_finalizers.append(msg.active_finalizers.cbegin(), msg.active_finalizers.cend()); } quorum_certificate_message to_msg() const { return {.proposal_id = proposal_id, - .active_finalizers = [this](){ std::string r; boost::to_string(active_finalizers, r); return r;}(), + .active_finalizers = [this]() { + std::vector r; + r.resize(active_finalizers.num_blocks()); + boost::to_block_range(active_finalizers, r.begin()); + return r; + }(), .active_agg_sig = active_agg_sig}; } void reset(const fc::sha256& proposal, size_t finalizer_size) { proposal_id = proposal; - active_finalizers = boost::dynamic_bitset<>{finalizer_size}; + active_finalizers = hs_dynamic_bitset{finalizer_size}; active_agg_sig = fc::crypto::blslib::bls_signature(); quorum_met = false; } - const boost::dynamic_bitset<>& get_active_finalizers() const { + const hs_dynamic_bitset& get_active_finalizers() const { assert(!active_finalizers.empty()); return active_finalizers; } - void set_active_finalizers(const boost::dynamic_bitset<>& bs) { + void set_active_finalizers(const hs_dynamic_bitset& bs) { assert(!bs.empty()); active_finalizers = bs; } @@ -78,7 +84,7 @@ namespace eosio::hotstuff { private: friend struct fc::reflector; fc::sha256 proposal_id = NULL_PROPOSAL_ID; - boost::dynamic_bitset<> active_finalizers; //bitset encoding, following canonical order + hs_dynamic_bitset active_finalizers; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; bool quorum_met = false; // not serialized across network }; @@ -114,15 +120,15 @@ namespace eosio::hotstuff { // returns false if proposal with that same ID already exists at the store of its height bool insert_proposal(const hs_proposal_message& proposal); - uint32_t positive_bits_count(const boost::dynamic_bitset<>& finalizers); + uint32_t positive_bits_count(const hs_dynamic_bitset& finalizers); - boost::dynamic_bitset<> update_bitset(const boost::dynamic_bitset<>& finalizer_set, name finalizer); + hs_dynamic_bitset update_bitset(const hs_dynamic_bitset& finalizer_set, name finalizer); digest_type get_digest_to_sign(const block_id_type& block_id, uint8_t phase_counter, const fc::sha256& final_on_qc); //get digest to sign from proposal data void reset_qc(const fc::sha256& proposal_id); //reset current internal qc - bool evaluate_quorum(const extended_schedule& es, const boost::dynamic_bitset<>& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal + bool evaluate_quorum(const extended_schedule& es, const hs_dynamic_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal // qc.quorum_met has to be updated by the caller (if it wants to) based on the return value of this method bool is_quorum_met(const quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal); //check if quorum has been met over a proposal diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index b0530e082c..291680506b 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -128,13 +128,13 @@ namespace eosio { namespace hotstuff { #endif } - uint32_t qc_chain::positive_bits_count(const boost::dynamic_bitset<>& finalizers) { + uint32_t qc_chain::positive_bits_count(const hs_dynamic_bitset& finalizers) { return finalizers.count(); // the number of bits in this bitset that are set. } - boost::dynamic_bitset<> qc_chain::update_bitset(const boost::dynamic_bitset<>& finalizer_set, name finalizer ) { + hs_dynamic_bitset qc_chain::update_bitset(const hs_dynamic_bitset& finalizer_set, name finalizer ) { - boost::dynamic_bitset b( finalizer_set ); + hs_dynamic_bitset b( finalizer_set ); vector finalizers = _pacemaker->get_finalizers(); for (size_t i = 0; i < finalizers.size();i++) { if (finalizers[i] == finalizer) { @@ -223,7 +223,7 @@ namespace eosio { namespace hotstuff { return b; } - bool qc_chain::evaluate_quorum(const extended_schedule& es, const boost::dynamic_bitset<>& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal) { + bool qc_chain::evaluate_quorum(const extended_schedule& es, const hs_dynamic_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal) { if (positive_bits_count(finalizers) < _pacemaker->get_quorum_threshold()){ @@ -233,7 +233,7 @@ namespace eosio { namespace hotstuff { fc::crypto::blslib::bls_public_key agg_key; bool first = true; - for (boost::dynamic_bitset<>::size_type i = 0; i < finalizers.size(); ++i) { + for (hs_dynamic_bitset::size_type i = 0; i < finalizers.size(); ++i) { if (finalizers[i]){ //adding finalizer's key to the aggregate pub key if (first) { @@ -493,7 +493,7 @@ namespace eosio { namespace hotstuff { auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); - const boost::dynamic_bitset<>& finalizer_set = _current_qc.get_active_finalizers(); + const hs_dynamic_bitset& finalizer_set = _current_qc.get_active_finalizers(); if (finalizer_set.any()) _current_qc.set_active_agg_sig(fc::crypto::blslib::aggregate({_current_qc.get_active_agg_sig(), vote.sig })); else From c2c0446a24e91b5ce7e92bd7769861d86f730dd4 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 09:31:13 -0500 Subject: [PATCH 099/151] GH-1547 Minor cleanup --- .../chain/include/eosio/chain/hotstuff.hpp | 2 +- .../include/eosio/hotstuff/qc_chain.hpp | 17 ++++++++--------- libraries/hotstuff/qc_chain.cpp | 12 ++++++------ 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 4b119fca70..e2020f1c5a 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -13,7 +13,7 @@ namespace eosio::chain { const block_id_type NULL_BLOCK_ID = block_id_type("00"); const fc::sha256 NULL_PROPOSAL_ID = fc::sha256("00"); - using hs_dynamic_bitset = boost::dynamic_bitset; + using hs_bitset = boost::dynamic_bitset; inline uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) { return (uint64_t{block_height} << 32) | phase_counter; diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 001a3c03a4..99d173f1f5 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -38,9 +38,8 @@ namespace eosio::hotstuff { explicit quorum_certificate(const quorum_certificate_message& msg) : proposal_id(msg.proposal_id) - , active_finalizers() + , active_finalizers(msg.active_finalizers.cbegin(), msg.active_finalizers.cend()) , active_agg_sig(msg.active_agg_sig) { - active_finalizers.append(msg.active_finalizers.cbegin(), msg.active_finalizers.cend()); } quorum_certificate_message to_msg() const { @@ -56,16 +55,16 @@ namespace eosio::hotstuff { void reset(const fc::sha256& proposal, size_t finalizer_size) { proposal_id = proposal; - active_finalizers = hs_dynamic_bitset{finalizer_size}; + active_finalizers = hs_bitset{finalizer_size}; active_agg_sig = fc::crypto::blslib::bls_signature(); quorum_met = false; } - const hs_dynamic_bitset& get_active_finalizers() const { + const hs_bitset& get_active_finalizers() const { assert(!active_finalizers.empty()); return active_finalizers; } - void set_active_finalizers(const hs_dynamic_bitset& bs) { + void set_active_finalizers(const hs_bitset& bs) { assert(!bs.empty()); active_finalizers = bs; } @@ -84,7 +83,7 @@ namespace eosio::hotstuff { private: friend struct fc::reflector; fc::sha256 proposal_id = NULL_PROPOSAL_ID; - hs_dynamic_bitset active_finalizers; //bitset encoding, following canonical order + hs_bitset active_finalizers; //bitset encoding, following canonical order fc::crypto::blslib::bls_signature active_agg_sig; bool quorum_met = false; // not serialized across network }; @@ -120,15 +119,15 @@ namespace eosio::hotstuff { // returns false if proposal with that same ID already exists at the store of its height bool insert_proposal(const hs_proposal_message& proposal); - uint32_t positive_bits_count(const hs_dynamic_bitset& finalizers); + uint32_t positive_bits_count(const hs_bitset& finalizers); - hs_dynamic_bitset update_bitset(const hs_dynamic_bitset& finalizer_set, name finalizer); + hs_bitset update_bitset(const hs_bitset& finalizer_set, name finalizer); digest_type get_digest_to_sign(const block_id_type& block_id, uint8_t phase_counter, const fc::sha256& final_on_qc); //get digest to sign from proposal data void reset_qc(const fc::sha256& proposal_id); //reset current internal qc - bool evaluate_quorum(const extended_schedule& es, const hs_dynamic_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal + bool evaluate_quorum(const extended_schedule& es, const hs_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal // qc.quorum_met has to be updated by the caller (if it wants to) based on the return value of this method bool is_quorum_met(const quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal); //check if quorum has been met over a proposal diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 291680506b..c6aede4ae4 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -128,13 +128,13 @@ namespace eosio { namespace hotstuff { #endif } - uint32_t qc_chain::positive_bits_count(const hs_dynamic_bitset& finalizers) { + uint32_t qc_chain::positive_bits_count(const hs_bitset& finalizers) { return finalizers.count(); // the number of bits in this bitset that are set. } - hs_dynamic_bitset qc_chain::update_bitset(const hs_dynamic_bitset& finalizer_set, name finalizer ) { + hs_bitset qc_chain::update_bitset(const hs_bitset& finalizer_set, name finalizer ) { - hs_dynamic_bitset b( finalizer_set ); + hs_bitset b(finalizer_set ); vector finalizers = _pacemaker->get_finalizers(); for (size_t i = 0; i < finalizers.size();i++) { if (finalizers[i] == finalizer) { @@ -223,7 +223,7 @@ namespace eosio { namespace hotstuff { return b; } - bool qc_chain::evaluate_quorum(const extended_schedule& es, const hs_dynamic_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal) { + bool qc_chain::evaluate_quorum(const extended_schedule& es, const hs_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal) { if (positive_bits_count(finalizers) < _pacemaker->get_quorum_threshold()){ @@ -233,7 +233,7 @@ namespace eosio { namespace hotstuff { fc::crypto::blslib::bls_public_key agg_key; bool first = true; - for (hs_dynamic_bitset::size_type i = 0; i < finalizers.size(); ++i) { + for (hs_bitset::size_type i = 0; i < finalizers.size(); ++i) { if (finalizers[i]){ //adding finalizer's key to the aggregate pub key if (first) { @@ -493,7 +493,7 @@ namespace eosio { namespace hotstuff { auto increment_version = fc::make_scoped_exit([this]() { ++_state_version; }); - const hs_dynamic_bitset& finalizer_set = _current_qc.get_active_finalizers(); + const hs_bitset& finalizer_set = _current_qc.get_active_finalizers(); if (finalizer_set.any()) _current_qc.set_active_agg_sig(fc::crypto::blslib::aggregate({_current_qc.get_active_agg_sig(), vote.sig })); else From 6af3110504745e4fec95e1c286a5ae8cbb056ac2 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 11:55:50 -0500 Subject: [PATCH 100/151] GH-1519 Use a std::variant for hotstuff messages --- .../chain/include/eosio/chain/hotstuff.hpp | 2 + libraries/hotstuff/chain_pacemaker.cpp | 34 +++--- .../eosio/hotstuff/chain_pacemaker.hpp | 22 ++-- plugins/chain_plugin/chain_plugin.cpp | 31 +----- .../eosio/chain_plugin/chain_plugin.hpp | 12 +- .../include/eosio/net_plugin/protocol.hpp | 5 +- plugins/net_plugin/net_plugin.cpp | 105 ++---------------- 7 files changed, 44 insertions(+), 167 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index e51d6968fb..962b6e06a5 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -54,6 +54,8 @@ namespace eosio::chain { quorum_certificate high_qc; //justification }; + using hs_message = std::variant; + struct finalizer_state { bool chained_mode = false; diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index e4d4c238e4..54a665e1a1 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -107,21 +107,10 @@ namespace eosio { namespace hotstuff { { } - void chain_pacemaker::register_bcast_functions( - std::function on_proposal_message, - std::function on_vote_message, - std::function on_new_block_message, - std::function on_new_view_message - ) { - FC_ASSERT(on_proposal_message, "on_proposal_message must be provided"); - FC_ASSERT(on_vote_message, "on_proposal_message must be provided"); - FC_ASSERT(on_new_block_message, "on_proposal_message must be provided"); - FC_ASSERT(on_new_view_message, "on_proposal_message must be provided"); + void chain_pacemaker::register_bcast_function(std::function on_hs_message) { + FC_ASSERT(on_hs_message, "on_hs_message must be provided"); std::lock_guard g( _hotstuff_global_mutex ); // not actually needed but doesn't hurt - bcast_proposal_message = std::move(on_proposal_message); - bcast_vote_message = std::move(on_vote_message); - bcast_new_block_message = std::move(on_new_block_message); - bcast_new_view_message = std::move(on_new_view_message); + bcast_hs_message = std::move(on_hs_message); } // Called internally by the chain_pacemaker to decide whether it should do something or not, based on feature activation. @@ -282,19 +271,28 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, name id) { - bcast_proposal_message(msg); + bcast_hs_message(msg); } void chain_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, name id) { - bcast_vote_message(msg); + bcast_hs_message(msg); } void chain_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, name id) { - bcast_new_block_message(msg); + bcast_hs_message(msg); } void chain_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, name id) { - bcast_new_view_message(msg); + bcast_hs_message(msg); + } + + void chain_pacemaker::on_hs_msg(const eosio::chain::hs_message &msg) { + std::visit(overloaded{ + [this](const hs_vote_message& m) { on_hs_vote_msg(m); }, + [this](const hs_proposal_message& m) { on_hs_proposal_msg(m); }, + [this](const hs_new_block_message& m) { on_hs_new_block_msg(m); }, + [this](const hs_new_view_message& m) { on_hs_new_view_msg(m); }, + }, msg); } // called from net threads diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index 8730a1b206..b0791ecedc 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -17,19 +17,11 @@ namespace eosio::hotstuff { //class-specific functions chain_pacemaker(controller* chain, std::set my_producers, fc::logger& logger); - void register_bcast_functions( - std::function on_proposal_message, - std::function on_vote_message, - std::function on_new_block_message, - std::function on_new_view_message - ); + void register_bcast_function(std::function on_hs_message); void beat(); - 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 - void on_hs_new_view_msg(const hs_new_view_message& msg); //new view msg event handler - void on_hs_new_block_msg(const hs_new_block_message& msg); //new block msg event handler + void on_hs_msg(const hs_message& msg); void get_state(finalizer_state& fs) const; @@ -57,6 +49,11 @@ namespace eosio::hotstuff { // Check if consensus upgrade feature is activated bool enabled() const; + 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 + void on_hs_new_view_msg(const hs_new_view_message& msg); //new view msg event handler + void on_hs_new_block_msg(const hs_new_block_message& msg); //new block msg event handler + // This serializes all messages (high-level requests) to the qc_chain core. // For maximum safety, the qc_chain core will only process one request at a time. // These requests can come directly from the net threads, or indirectly from a @@ -73,10 +70,7 @@ namespace eosio::hotstuff { chain::controller* _chain = nullptr; qc_chain _qc_chain; - std::function bcast_proposal_message; - std::function bcast_vote_message; - std::function bcast_new_block_message; - std::function bcast_new_view_message; + std::function bcast_hs_message; uint32_t _quorum_threshold = 15; //FIXME/TODO: calculate from schedule fc::logger& _logger; diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 010408dd84..517d4fb67c 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1119,17 +1119,9 @@ void chain_plugin::create_pacemaker(std::set my_producers) my->_chain_pacemaker.emplace(&chain(), std::move(my_producers), hotstuff_logger); } -void chain_plugin::register_pacemaker_bcast_functions( - std::function on_proposal_message, - std::function on_vote_message, - std::function on_new_block_message, - std::function on_new_view_message) { +void chain_plugin::register_pacemaker_bcast_function(std::function on_hs_message) { EOS_ASSERT( my->_chain_pacemaker, plugin_config_exception, "chain_pacemaker not created" ); - my->_chain_pacemaker->register_bcast_functions( - std::move(on_proposal_message), - std::move(on_vote_message), - std::move(on_new_block_message), - std::move(on_new_view_message)); + my->_chain_pacemaker->register_bcast_function(std::move(on_hs_message)); } @@ -2691,23 +2683,8 @@ read_only::get_finalizer_state(const get_finalizer_state_params&, const fc::time } // namespace chain_apis // called from net threads -void chain_plugin::notify_hs_vote_message( const hs_vote_message& msg ) { - my->_chain_pacemaker->on_hs_vote_msg(msg); -}; - -// called from net threads -void chain_plugin::notify_hs_proposal_message( const hs_proposal_message& msg ) { - my->_chain_pacemaker->on_hs_proposal_msg(msg); -}; - -// called from net threads -void chain_plugin::notify_hs_new_view_message( const hs_new_view_message& msg ) { - my->_chain_pacemaker->on_hs_new_view_msg(msg); -}; - -// called from net threads -void chain_plugin::notify_hs_new_block_message( const hs_new_block_message& msg ) { - my->_chain_pacemaker->on_hs_new_block_msg(msg); +void chain_plugin::notify_hs_message( const hs_message& msg ) { + my->_chain_pacemaker->on_hs_msg(msg); }; void chain_plugin::notify_hs_block_produced() { diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 1e3bffb831..bcdb27fc0b 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -1032,16 +1032,8 @@ class chain_plugin : public plugin { const controller& chain() const; void create_pacemaker(std::set my_producers); - void register_pacemaker_bcast_functions( - std::function on_proposal_message, - std::function on_vote_message, - std::function on_new_block_message, - std::function on_new_view_message - ); - void notify_hs_vote_message( const chain::hs_vote_message& msg ); - void notify_hs_proposal_message( const chain::hs_proposal_message& msg ); - void notify_hs_new_view_message( const chain::hs_new_view_message& msg ); - void notify_hs_new_block_message( const chain::hs_new_block_message& msg ); + void register_pacemaker_bcast_function(std::function on_hs_message); + void notify_hs_message( const chain::hs_message& msg ); void notify_hs_block_produced(); chain::chain_id_type get_chain_id() const; diff --git a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp index f291596bac..811885768a 100644 --- a/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp +++ b/plugins/net_plugin/include/eosio/net_plugin/protocol.hpp @@ -142,10 +142,7 @@ namespace eosio { sync_request_message, signed_block, packed_transaction, - hs_vote_message, - hs_proposal_message, - hs_new_view_message, - hs_new_block_message>; + hs_message>; } // namespace eosio diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 68621f32e2..2fe5e275c8 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -495,10 +495,7 @@ namespace eosio { void transaction_ack(const std::pair&); void on_irreversible_block( const block_state_ptr& block ); - void on_hs_proposal_message( const hs_proposal_message& msg ); - void on_hs_vote_message( const hs_vote_message& msg ); - void on_hs_new_view_message( const hs_new_view_message& msg ); - void on_hs_new_block_message( const hs_new_block_message& msg ); + void on_hs_message( const hs_message& msg ); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_expire_timer(); @@ -1038,15 +1035,11 @@ namespace eosio { void handle_message( const block_id_type& id, signed_block_ptr ptr ); void handle_message( const packed_transaction& msg ) = delete; // packed_transaction_ptr overload used instead void handle_message( packed_transaction_ptr trx ); + void handle_message( const hs_message& msg ); // returns calculated number of blocks combined latency uint32_t calc_block_latency(); - void handle_message( const hs_vote_message& msg ); - void handle_message( const hs_proposal_message& msg ); - void handle_message( const hs_new_view_message& msg ); - void handle_message( const hs_new_block_message& msg ); - void process_signed_block( const block_id_type& id, signed_block_ptr block, block_state_ptr bsp ); fc::variant_object get_logger_variant() const { @@ -1124,30 +1117,12 @@ namespace eosio { c->handle_message( msg ); } - void operator()( const hs_vote_message& msg ) const { + void operator()( const hs_message& msg ) const { // continue call to handle_message on connection strand peer_dlog( c, "handle hs_vote_message" ); c->handle_message( msg ); } - void operator()( const hs_proposal_message& msg ) const { - // continue call to handle_message on connection strand - peer_dlog( c, "handle hs_proposal_message" ); - c->handle_message( msg ); - } - void operator()( const hs_new_view_message& msg ) const { - // continue call to handle_message on connection strand - peer_dlog( c, "handle hs_new_view_message" ); - c->handle_message( msg ); - } - void operator()( const hs_new_block_message& msg ) const { - // continue call to handle_message on connection strand - peer_dlog( c, "handle hs_new_block_message" ); - c->handle_message( msg ); - } - - }; - std::tuple split_host_port_type(const std::string& peer_add) { @@ -3586,24 +3561,9 @@ namespace eosio { } } - void connection::handle_message( const hs_vote_message& msg ) { - peer_dlog(this, "received vote: ${msg}", ("msg", msg)); - my_impl->chain_plug->notify_hs_vote_message(msg); - } - - void connection::handle_message( const hs_proposal_message& msg ) { - peer_dlog(this, "received proposal: ${msg}", ("msg", msg)); - my_impl->chain_plug->notify_hs_proposal_message(msg); - } - - void connection::handle_message( const hs_new_view_message& msg ) { - peer_dlog(this, "received new view: ${msg}", ("msg", msg)); - my_impl->chain_plug->notify_hs_new_view_message(msg); - } - - void connection::handle_message( const hs_new_block_message& msg ) { - peer_dlog(this, "received new block msg: ${msg}", ("msg", msg)); - my_impl->chain_plug->notify_hs_new_block_message(msg); + void connection::handle_message( const hs_message& msg ) { + peer_dlog(this, "received hs: ${msg}", ("msg", msg)); + my_impl->chain_plug->notify_hs_message(msg); } size_t calc_trx_size( const packed_transaction_ptr& trx ) { @@ -3857,41 +3817,8 @@ namespace eosio { on_active_schedule(chain_plug->chain().active_producers()); } - void net_plugin_impl::on_hs_proposal_message( const hs_proposal_message& msg ) { - fc_dlog(logger, "sending proposal msg: ${msg}", ("msg", msg)); - - buffer_factory buff_factory; - auto send_buffer = buff_factory.get_send_buffer( msg ); - - dispatcher->strand.post( [this, msg{std::move(send_buffer)}]() mutable { - dispatcher->bcast_msg( std::move(msg) ); - }); - } - - void net_plugin_impl::on_hs_vote_message( const hs_vote_message& msg ) { - fc_dlog(logger, "sending vote msg: ${msg}", ("msg", msg)); - - buffer_factory buff_factory; - auto send_buffer = buff_factory.get_send_buffer( msg ); - - dispatcher->strand.post( [this, msg{std::move(send_buffer)}]() mutable { - dispatcher->bcast_msg( std::move(msg) ); - }); - } - - void net_plugin_impl::on_hs_new_view_message( const hs_new_view_message& msg ) { - fc_dlog(logger, "sending new_view msg: ${msg}", ("msg", msg)); - - buffer_factory buff_factory; - auto send_buffer = buff_factory.get_send_buffer( msg ); - - dispatcher->strand.post( [this, msg{std::move(send_buffer)}]() mutable { - dispatcher->bcast_msg( std::move(msg) ); - }); - } - - void net_plugin_impl::on_hs_new_block_message( const hs_new_block_message& msg ) { - fc_dlog(logger, "sending new_block msg: ${msg}", ("msg", msg)); + void net_plugin_impl::on_hs_message( const hs_message& msg ) { + fc_dlog(logger, "sending hs msg: ${msg}", ("msg", msg)); buffer_factory buff_factory; auto send_buffer = buff_factory.get_send_buffer( msg ); @@ -4225,21 +4152,11 @@ namespace eosio { chain_plug->enable_accept_transactions(); } - chain_plug->register_pacemaker_bcast_functions( - [my = shared_from_this()](const hs_proposal_message& s) { - my->on_hs_proposal_message(s); - }, - [my = shared_from_this()](const hs_vote_message& s) { - my->on_hs_vote_message(s); - }, - [my = shared_from_this()](const hs_new_block_message& s) { - my->on_hs_new_block_message(s); - }, - [my = shared_from_this()](const hs_new_view_message& s) { - my->on_hs_new_view_message(s); + chain_plug->register_pacemaker_bcast_function( + [my = shared_from_this()](const hs_message& s) { + my->on_hs_message(s); } ); - } FC_LOG_AND_RETHROW() } From dba1f3a5ec8d49f2336302ff9b7f36f617873bb6 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 13:37:25 -0500 Subject: [PATCH 101/151] GH-1541 Add thread safety to chain_pacemaker access of chain state --- libraries/chain/controller.cpp | 24 +++---- .../chain/include/eosio/chain/controller.hpp | 5 +- libraries/chain/webassembly/privileged.cpp | 3 +- libraries/hotstuff/chain_pacemaker.cpp | 67 ++++++++----------- .../include/eosio/hotstuff/base_pacemaker.hpp | 2 - .../eosio/hotstuff/chain_pacemaker.hpp | 16 +++-- libraries/hotstuff/qc_chain.cpp | 1 + plugins/chain_plugin/chain_plugin.cpp | 4 +- 8 files changed, 58 insertions(+), 64 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index cf81e2c7e2..2efbe13ab5 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -264,10 +264,8 @@ struct controller_impl { map< account_name, map > apply_handlers; unordered_map< builtin_protocol_feature_t, std::function, enum_hash > protocol_feature_activation_handlers; - // TODO: This probably wants to be something better; - // Storing when set_finalizers() is called; retrievable via get_finalizers() (called by chain_pacemaker) - uint64_t fthreshold = 0; - vector finalizers; + // TODO: This probably wants to be something better; store in chainbase and/or block_state + finalizer_set current_finalizer_set; void pop_block() { auto prev = fork_db.get_block( head->header.previous ); @@ -1995,13 +1993,9 @@ struct controller_impl { emit( self.new_hs_new_block_message, msg ); } - void set_finalizers_impl(uint64_t fthreshold, vector finalizers) { - this->fthreshold = fthreshold; - this->finalizers = std::move(finalizers); - } - - std::pair> get_finalizers_impl() const { - return { fthreshold, finalizers }; + void set_finalizers_impl(const finalizer_set fin_set) { + // TODO store in chainbase + current_finalizer_set = fin_set; } /** @@ -3327,12 +3321,12 @@ int64_t controller::set_proposed_producers( vector producers return version; } -void controller::set_finalizers( uint64_t fthreshold, vector finalizers ) { - my->set_finalizers_impl(fthreshold, std::move(finalizers)); +void controller::set_finalizers( const finalizer_set& fin_set ) { + my->set_finalizers_impl(fin_set); } -std::pair> controller::get_finalizers() const { - return my->get_finalizers_impl(); +const finalizer_set& controller::get_finalizers() const { + return my->current_finalizer_set; } const producer_authority_schedule& controller::active_producers()const { diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index a0f5b78d5a..29e471951e 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -30,6 +30,7 @@ namespace eosio { namespace chain { using hs_new_view_message_ptr = std::shared_ptr; using hs_new_block_message_ptr = std::shared_ptr; struct finalizer_authority; + struct finalizer_set; class authorization_manager; @@ -307,8 +308,8 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector producers ); - void set_finalizers( uint64_t fthreshold, vector finalizers ); - std::pair> get_finalizers() const; + void set_finalizers( const finalizer_set& fin_set ); + const finalizer_set& get_finalizers() const; bool light_validation_allowed() const; bool skip_auth_check()const; diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index b2a471d425..6ff8bf9713 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -158,6 +158,7 @@ namespace eosio { namespace chain { namespace webassembly { fc::raw::unpack(ds, finset); vector & finalizers = 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" ); @@ -177,7 +178,7 @@ namespace eosio { namespace chain { namespace webassembly { 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.fthreshold, std::move(finalizers) ); + context.control.set_finalizers( finset ); } uint32_t interface::get_blockchain_parameters_packed( legacy_span packed_blockchain_parameters ) const { diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 54d952622f..db3e673d37 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -105,18 +105,12 @@ namespace eosio { namespace hotstuff { _qc_chain("default"_n, this, std::move(my_producers), logger), _logger(logger) { - } - - // Called internally by the chain_pacemaker to decide whether it should do something or not, based on feature activation. - // Only methods called by the outside need to call this; methods called by qc_chain only don't need to check for enable(). - bool chain_pacemaker::enabled() const { - return _chain->is_builtin_activated( builtin_protocol_feature_t::instant_finality ); + _accepted_block_connection = chain->accepted_block.connect( [this]( const block_state_ptr& blk ) { + on_accepted_block( blk ); + } ); } void chain_pacemaker::get_state(finalizer_state& fs) const { - if (! enabled()) - return; - // lock-free state version check uint64_t current_state_version = _qc_chain.get_state_version(); if (_state_cache_version != current_state_version) { @@ -141,12 +135,6 @@ namespace eosio { namespace hotstuff { fs = _state_cache; } - name chain_pacemaker::get_proposer() { - const block_state_ptr& hbs = _chain->head_block_state(); - name n = hbs->header.producer; - return n; - } - name chain_pacemaker::debug_leader_remap(name n) { /* // FIXME/REMOVE: simple device to test proposer/leader @@ -212,9 +200,22 @@ namespace eosio { namespace hotstuff { return n; } + // called from main thread + void chain_pacemaker::on_accepted_block( const block_state_ptr& blk ) { + std::scoped_lock g( _chain_state_mutex ); + _head_block_state = blk; + _finalizer_set = _chain->get_finalizers(); // TODO get from chainbase or from block_state + } + + name chain_pacemaker::get_proposer() { + std::scoped_lock g( _chain_state_mutex ); + return _head_block_state->header.producer; + } + name chain_pacemaker::get_leader() { - const block_state_ptr& hbs = _chain->head_block_state(); - name n = hbs->header.producer; + std::unique_lock g( _chain_state_mutex ); + name n = _head_block_state->header.producer; + g.unlock(); // FIXME/REMOVE: testing leader/proposer separation n = debug_leader_remap(n); @@ -223,10 +224,11 @@ namespace eosio { namespace hotstuff { } name chain_pacemaker::get_next_leader() { - const block_state_ptr& hbs = _chain->head_block_state(); - block_timestamp_type next_block_time = hbs->header.timestamp.next(); - producer_authority p_auth = hbs->get_scheduled_producer(next_block_time); + std::unique_lock g( _chain_state_mutex ); + block_timestamp_type next_block_time = _head_block_state->header.timestamp.next(); + producer_authority p_auth = _head_block_state->get_scheduled_producer(next_block_time); name n = p_auth.producer_name; + g.unlock(); // FIXME/REMOVE: testing leader/proposer separation n = debug_leader_remap(n); @@ -249,11 +251,11 @@ namespace eosio { namespace hotstuff { // - 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 // - auto [threshold, finalizers] = _chain->get_finalizers(); + std::unique_lock g( _chain_state_mutex ); + const auto& fin_set = _chain->get_finalizers(); // TODO use // Old code: get eosio::name from the producer schedule - const block_state_ptr& hbs = _chain->head_block_state(); - const std::vector& pa_list = hbs->active_schedule.producers; + const std::vector& pa_list = _head_block_state->active_schedule.producers; std::vector pn_list; pn_list.reserve(pa_list.size()); std::transform(pa_list.begin(), pa_list.end(), @@ -263,17 +265,16 @@ namespace eosio { namespace hotstuff { } block_id_type chain_pacemaker::get_current_block_id() { - return _chain->head_block_id(); + std::scoped_lock g( _chain_state_mutex ); + return _head_block_state->id; } uint32_t chain_pacemaker::get_quorum_threshold() { return _quorum_threshold; } + // called from the main application thread void chain_pacemaker::beat() { - if (! enabled()) - return; - csc prof("beat"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -302,9 +303,6 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_proposal_msg(const hs_proposal_message& msg) { - if (! enabled()) - return; - csc prof("prop"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -313,9 +311,6 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_vote_msg(const hs_vote_message& msg) { - if (! enabled()) - return; - csc prof("vote"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -324,9 +319,6 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_new_block_msg(const hs_new_block_message& msg) { - if (! enabled()) - return; - csc prof("nblk"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); @@ -335,9 +327,6 @@ namespace eosio { namespace hotstuff { } void chain_pacemaker::on_hs_new_view_msg(const hs_new_view_message& msg) { - if (! enabled()) - return; - csc prof("view"); std::lock_guard g( _hotstuff_global_mutex ); prof.core_in(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index 7b264b28dc..7fce189948 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -30,8 +30,6 @@ namespace eosio::hotstuff { virtual chain::block_id_type get_current_block_id() = 0; - //hotstuff getters. todo : implement relevant setters as host functions -#warning hotstuff getters. todo : implement relevant setters as host functions virtual chain::name get_proposer() = 0; virtual chain::name get_leader() = 0; virtual chain::name get_next_leader() = 0; diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index f2451d267b..299273b314 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -5,6 +5,8 @@ #include +#include + #include namespace eosio::chain { @@ -45,14 +47,14 @@ namespace eosio::hotstuff { void send_hs_new_view_msg(const hs_new_view_message& msg, name id); void send_hs_new_block_msg(const hs_new_block_message& msg, name id); + private: + void on_accepted_block( const block_state_ptr& blk ); + private: //FIXME/REMOVE: for testing/debugging only name debug_leader_remap(name n); - // Check if consensus upgrade feature is activated - bool enabled() const; - // This serializes all messages (high-level requests) to the qc_chain core. // For maximum safety, the qc_chain core will only process one request at a time. // These requests can come directly from the net threads, or indirectly from a @@ -66,7 +68,13 @@ namespace eosio::hotstuff { mutable finalizer_state _state_cache; mutable std::atomic _state_cache_version = 0; - chain::controller* _chain = nullptr; + chain::controller* _chain = nullptr; // TODO will not be needed once this is merged with PR#1559 + + mutable std::mutex _chain_state_mutex; + block_state_ptr _head_block_state; + finalizer_set _finalizer_set; + + boost::signals2::scoped_connection _accepted_block_connection; qc_chain _qc_chain; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 94d43cdb2b..5bc1989664 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -674,6 +674,7 @@ namespace eosio { namespace hotstuff { } // Invoked when we could perhaps make a proposal to the network (or to ourselves, if we are the leader). + // Called from the main application thread void qc_chain::on_beat(){ // Non-proposing leaders do not care about on_beat(), because leaders react to a block proposal diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 404803ea8b..c3a383da51 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -2692,7 +2692,9 @@ void chain_plugin::notify_hs_new_block_message( const hs_new_block_message& msg }; void chain_plugin::notify_hs_block_produced() { - my->_chain_pacemaker->beat(); + if (chain().is_builtin_activated( builtin_protocol_feature_t::instant_finality )) { + my->_chain_pacemaker->beat(); + } } fc::variant chain_plugin::get_log_trx_trace(const transaction_trace_ptr& trx_trace ) const { From 55936b13b59b357ccb349fe68af17c8322d6d830 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 13:51:24 -0500 Subject: [PATCH 102/151] GH-1519 Rename method to be more clear --- plugins/net_plugin/net_plugin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 2fe5e275c8..07cd52f3a3 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -495,7 +495,7 @@ namespace eosio { void transaction_ack(const std::pair&); void on_irreversible_block( const block_state_ptr& block ); - void on_hs_message( const hs_message& msg ); + void bcast_hs_message( const hs_message& msg ); void start_conn_timer(boost::asio::steady_timer::duration du, std::weak_ptr from_connection); void start_expire_timer(); @@ -1119,7 +1119,7 @@ namespace eosio { void operator()( const hs_message& msg ) const { // continue call to handle_message on connection strand - peer_dlog( c, "handle hs_vote_message" ); + peer_dlog( c, "handle hs_message" ); c->handle_message( msg ); } }; @@ -3817,7 +3817,7 @@ namespace eosio { on_active_schedule(chain_plug->chain().active_producers()); } - void net_plugin_impl::on_hs_message( const hs_message& msg ) { + void net_plugin_impl::bcast_hs_message( const hs_message& msg ) { fc_dlog(logger, "sending hs msg: ${msg}", ("msg", msg)); buffer_factory buff_factory; @@ -4154,7 +4154,7 @@ namespace eosio { chain_plug->register_pacemaker_bcast_function( [my = shared_from_this()](const hs_message& s) { - my->on_hs_message(s); + my->bcast_hs_message(s); } ); } FC_LOG_AND_RETHROW() From 79bdc0433f02f64a1c3eda6a12a64236816daf34 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 14:06:42 -0500 Subject: [PATCH 103/151] GH-1519 Rename method to be more clear --- libraries/hotstuff/chain_pacemaker.cpp | 6 +++--- .../hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp | 2 +- plugins/chain_plugin/chain_plugin.cpp | 4 ++-- .../include/eosio/chain_plugin/chain_plugin.hpp | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 54a665e1a1..1b3f62801c 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -107,10 +107,10 @@ namespace eosio { namespace hotstuff { { } - void chain_pacemaker::register_bcast_function(std::function on_hs_message) { - FC_ASSERT(on_hs_message, "on_hs_message must be provided"); + void chain_pacemaker::register_bcast_function(std::function broadcast_hs_message) { + FC_ASSERT(broadcast_hs_message, "on_hs_message must be provided"); std::lock_guard g( _hotstuff_global_mutex ); // not actually needed but doesn't hurt - bcast_hs_message = std::move(on_hs_message); + bcast_hs_message = std::move(broadcast_hs_message); } // Called internally by the chain_pacemaker to decide whether it should do something or not, based on feature activation. diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index b0791ecedc..aa8e1f0c4c 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -17,7 +17,7 @@ namespace eosio::hotstuff { //class-specific functions chain_pacemaker(controller* chain, std::set my_producers, fc::logger& logger); - void register_bcast_function(std::function on_hs_message); + void register_bcast_function(std::function broadcast_hs_message); void beat(); diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 517d4fb67c..ae2512371e 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1119,9 +1119,9 @@ void chain_plugin::create_pacemaker(std::set my_producers) my->_chain_pacemaker.emplace(&chain(), std::move(my_producers), hotstuff_logger); } -void chain_plugin::register_pacemaker_bcast_function(std::function on_hs_message) { +void chain_plugin::register_pacemaker_bcast_function(std::function bcast_hs_message) { EOS_ASSERT( my->_chain_pacemaker, plugin_config_exception, "chain_pacemaker not created" ); - my->_chain_pacemaker->register_bcast_function(std::move(on_hs_message)); + my->_chain_pacemaker->register_bcast_function(std::move(bcast_hs_message)); } diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index bcdb27fc0b..150f1ea855 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -1032,7 +1032,7 @@ class chain_plugin : public plugin { const controller& chain() const; void create_pacemaker(std::set my_producers); - void register_pacemaker_bcast_function(std::function on_hs_message); + void register_pacemaker_bcast_function(std::function bcast_hs_message); void notify_hs_message( const chain::hs_message& msg ); void notify_hs_block_produced(); From cb8bc49c14c52a2972002d7b894124cee3fb7394 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 14:31:44 -0500 Subject: [PATCH 104/151] GH-1541 minor cleanup --- libraries/chain/controller.cpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 2efbe13ab5..b396fb3d18 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -1993,7 +1993,7 @@ struct controller_impl { emit( self.new_hs_new_block_message, msg ); } - void set_finalizers_impl(const finalizer_set fin_set) { + void set_finalizers_impl(const finalizer_set& fin_set) { // TODO store in chainbase current_finalizer_set = fin_set; } diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index db3e673d37..fc986080f2 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -227,8 +227,8 @@ namespace eosio { namespace hotstuff { std::unique_lock g( _chain_state_mutex ); block_timestamp_type next_block_time = _head_block_state->header.timestamp.next(); producer_authority p_auth = _head_block_state->get_scheduled_producer(next_block_time); - name n = p_auth.producer_name; g.unlock(); + name n = p_auth.producer_name; // FIXME/REMOVE: testing leader/proposer separation n = debug_leader_remap(n); From a7fc539f12e60b8cfb714f8999a1ccd400df2101 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 14:48:27 -0500 Subject: [PATCH 105/151] GH-1541 minor cleanup --- libraries/chain/include/eosio/chain/finalizer_set.hpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 5d669fd44a..a31668cf6c 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -100,7 +100,7 @@ namespace eosio::chain { } uint32_t version = 0; ///< sequentially incrementing version number - uint64_t fthreshold; // vote fweight threshold to finalize blocks + 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 ) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index fc986080f2..1f61a72ed2 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -204,6 +204,7 @@ 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 } @@ -253,9 +254,11 @@ namespace eosio { namespace hotstuff { // 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(); // Old code: get eosio::name from the producer schedule - const std::vector& pa_list = _head_block_state->active_schedule.producers; + const std::vector& pa_list = hbs->active_schedule.producers; std::vector pn_list; pn_list.reserve(pa_list.size()); std::transform(pa_list.begin(), pa_list.end(), From 7f4bcf8a1b70477493cbea174ccf2a58adeebedc Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Mon, 28 Aug 2023 15:36:49 -0500 Subject: [PATCH 106/151] GH-1541 make sure head_block_state is initialized --- libraries/hotstuff/chain_pacemaker.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 1f61a72ed2..d0d2389931 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -108,6 +108,7 @@ namespace eosio { namespace hotstuff { _accepted_block_connection = chain->accepted_block.connect( [this]( const block_state_ptr& blk ) { on_accepted_block( blk ); } ); + _head_block_state = chain->head_block_state(); } void chain_pacemaker::get_state(finalizer_state& fs) const { From 7447c157a9e4978cb5c100ef0998a51b7c001d48 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 29 Aug 2023 07:30:53 -0500 Subject: [PATCH 107/151] GH-1541 make sure head_block_state is initialized --- libraries/chain/include/eosio/chain/finalizer_set.hpp | 2 +- plugins/chain_plugin/chain_plugin.cpp | 1 - plugins/producer_plugin/producer_plugin.cpp | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index a31668cf6c..42dc355b1b 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -48,7 +48,7 @@ namespace eosio::chain { struct finalizer_authority { std::string description; - uint64_t fweight; // weight that this finalizer's vote has for meeting fthreshold + uint64_t fweight = 0; // weight that this finalizer's vote has for meeting fthreshold fc::crypto::blslib::bls_public_key public_key; auto to_shared(chainbase::allocator alloc) const { diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index c3a383da51..11fb9faa1b 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1128,7 +1128,6 @@ void chain_plugin_impl::plugin_startup() { try { EOS_ASSERT( chain_config->read_mode != db_read_mode::IRREVERSIBLE || !accept_transactions, plugin_config_exception, "read-mode = irreversible. transactions should not be enabled by enable_accept_transactions" ); - EOS_ASSERT( _chain_pacemaker, plugin_config_exception, "chain_pacemaker not initialization" ); try { auto shutdown = [](){ return app().quit(); }; auto check_shutdown = [](){ return app().is_quiting(); }; diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 4384c52c56..054068b25a 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -1326,8 +1326,6 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia _snapshot_scheduler.set_db_path(_snapshots_dir); _snapshot_scheduler.set_snapshots_path(_snapshots_dir); - - chain_plug->create_pacemaker(_producers); } void producer_plugin::plugin_initialize(const boost::program_options::variables_map& options) { @@ -1360,6 +1358,8 @@ void producer_plugin_impl::plugin_startup() { EOS_ASSERT(_producers.empty() || chain_plug->accept_transactions(), plugin_config_exception, "node cannot have any producer-name configured because no block production is possible with no [api|p2p]-accepted-transactions"); + chain_plug->create_pacemaker(_producers); + _accepted_block_connection.emplace(chain.accepted_block.connect([this](const auto& bsp) { on_block(bsp); })); _accepted_block_header_connection.emplace(chain.accepted_block_header.connect([this](const auto& bsp) { on_block_header(bsp); })); _irreversible_block_connection.emplace( From 683750a38f0360f2cffd46c501cc927354908a44 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 29 Aug 2023 09:47:09 -0500 Subject: [PATCH 108/151] chain_pacemaker now created in startup. --- plugins/net_plugin/net_plugin.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 07cd52f3a3..a8bb78dc00 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -4152,17 +4152,17 @@ namespace eosio { chain_plug->enable_accept_transactions(); } - chain_plug->register_pacemaker_bcast_function( - [my = shared_from_this()](const hs_message& s) { - my->bcast_hs_message(s); - } ); - } FC_LOG_AND_RETHROW() } void net_plugin_impl::plugin_startup() { fc_ilog( logger, "my node_id is ${id}", ("id", node_id )); + chain_plug->register_pacemaker_bcast_function( + [my = shared_from_this()](const hs_message& s) { + my->bcast_hs_message(s); + } ); + producer_plug = app().find_plugin(); set_producer_accounts(producer_plug->producer_accounts()); From 36a60e11defd132c89a83dd25aff47718eb6e99a Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 29 Aug 2023 20:04:21 -0500 Subject: [PATCH 109/151] Remove unneeded/unused shared versions --- .../include/eosio/chain/finalizer_set.hpp | 68 ------------------- 1 file changed, 68 deletions(-) diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index 42dc355b1b..ca5630ade1 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -10,55 +10,12 @@ namespace eosio::chain { - struct shared_finalizer_authority { - 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 std::string& description, const uint64_t fweight, const fc::crypto::blslib::bls_public_key& public_key ) - :description(description) - ,fweight(fweight) - ,public_key(public_key) - {} - -#warning FIXME: Must change std::string to shared_string. - std::string description; - uint64_t fweight; - fc::crypto::blslib::bls_public_key public_key; - }; - - struct shared_finalizer_set { - shared_finalizer_set() = delete; - - explicit shared_finalizer_set( chainbase::allocator 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 finalizers; - }; - 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 to_shared(chainbase::allocator alloc) const { - return shared_finalizer_authority(description, fweight, public_key); - } - - static auto from_shared( const shared_finalizer_authority& src ) { - return finalizer_authority { src.description, src.fweight, src.public_key }; - } - 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 ); } @@ -76,29 +33,6 @@ namespace eosio::chain { ,finalizers(finalizers) {} - auto to_shared(chainbase::allocator 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 = 0; // vote fweight threshold to finalize blocks vector finalizers; // Instant Finality voter set @@ -123,5 +57,3 @@ namespace 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::shared_finalizer_authority, (description)(fweight)(public_key) ) -FC_REFLECT( eosio::chain::shared_finalizer_set, (version)(fthreshold)(finalizers) ) From d82518df1d7b6f1acce5dbce3130de30637f5066 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Wed, 30 Aug 2023 10:27:16 -0400 Subject: [PATCH 110/151] Second pass at recursion removal for `qc_chain::commit()` --- libraries/hotstuff/qc_chain.cpp | 87 +++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 38 deletions(-) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index ed760d6d28..f6e14c7375 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -1,8 +1,7 @@ #include #include -#include - +#include /* Todo list / notes: @@ -44,7 +43,7 @@ -- skip BPs without a bls key in the selection, new host functions are available */ -namespace eosio { namespace hotstuff { +namespace eosio::hotstuff { const hs_proposal_message* qc_chain::get_proposal(const fc::sha256& proposal_id) { #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE @@ -1056,56 +1055,68 @@ namespace eosio { namespace hotstuff { } void qc_chain::commit(const hs_proposal_message& initial_proposal) { - std::stack proposal_stack; - proposal_stack.push(&initial_proposal); - - while (!proposal_stack.empty()) { - const hs_proposal_message* proposal = proposal_stack.top(); - proposal_stack.pop(); - - fc_tlog(_logger, " === attempting to commit proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", proposal->block_num())("proposal_id", proposal->proposal_id)("block_id", proposal->block_id) - ("phase_counter", proposal->phase_counter)("parent_id", proposal->parent_id)); - - bool exec_height_check = false; + std::vector proposal_chain; + proposal_chain.reserve(10); + + const hs_proposal_message* p = &initial_proposal; + while (p) { + fc_tlog(_logger, " === attempting to commit proposal #${block_num} ${prop_id} block_id: ${block_id} " + "phase: ${phase} parent_id: ${parent_id}", + ("block_num", p->block_num())("prop_id", p->proposal_id)("block_id", p->block_id) + ("phase", p->phase_counter)("parent_id", p->parent_id)); const hs_proposal_message* last_exec_prop = get_proposal(_b_exec); EOS_ASSERT(last_exec_prop != nullptr || _b_exec == NULL_PROPOSAL_ID, chain_exception, "expected hs_proposal ${id} not found", ("id", _b_exec)); if (last_exec_prop != nullptr) { - fc_tlog(_logger, " === _b_exec proposal #${block_num} ${proposal_id} block_id : ${block_id} phase : ${phase_counter} parent_id : ${parent_id}", - ("block_num", last_exec_prop->block_num())("proposal_id", last_exec_prop->proposal_id)("block_id", last_exec_prop->block_id) - ("phase_counter", last_exec_prop->phase_counter)("parent_id", last_exec_prop->parent_id)); - - fc_tlog(_logger, " *** last_exec_prop ${proposal_id_1} ${phase_counter_1} vs proposal ${proposal_id_2} ${phase_counter_2} ", - ("proposal_id_1", last_exec_prop->block_num())("phase_counter_1", last_exec_prop->phase_counter) - ("proposal_id_2", proposal->block_num())("phase_counter_2", proposal->phase_counter)); - } else { - fc_tlog(_logger, " === _b_exec proposal is null vs proposal ${proposal_id_2} ${phase_counter_2} ", - ("proposal_id_2", proposal->block_num())("phase_counter_2", proposal->phase_counter)); - } - - if (_b_exec == NULL_PROPOSAL_ID) { - exec_height_check = true; + fc_tlog(_logger, " === _b_exec proposal #${block_num} ${prop_id} block_id: ${block_id} " + "phase: ${phase} parent_id: ${parent_id}", + ("block_num", last_exec_prop->block_num())("prop_id", last_exec_prop->proposal_id) + ("block_id", last_exec_prop->block_id)("phase", last_exec_prop->phase_counter) + ("parent_id", last_exec_prop->parent_id)); + + fc_tlog(_logger, " *** last_exec_prop ${prop_id_1} ${phase_1} vs proposal ${prop_id_2} ${phase_2} ", + ("prop_id_1", last_exec_prop->block_num())("phase_1", last_exec_prop->phase_counter) + ("prop_id_2", p->block_num())("phase_2", p->phase_counter)); } else { - exec_height_check = last_exec_prop->get_height() < proposal->get_height(); + fc_tlog(_logger, " === _b_exec proposal is null vs proposal ${prop_id_2} ${phase_2} ", + ("prop_id_2", p->block_num())("phase_2", p->phase_counter)); } + bool exec_height_check = _b_exec == NULL_PROPOSAL_ID || last_exec_prop->get_height() < p->get_height(); if (exec_height_check) { - const hs_proposal_message* p = get_proposal(proposal->parent_id); - if (p != nullptr) { - proposal_stack.push(p); // Push the parent proposal onto the stack for processing + if (auto parent = get_proposal(p->parent_id); parent != nullptr) { + proposal_chain.push_back(parent); // add proposal to vector for further processing + p = parent; // process parent proposal next in while loop } + } else { + fc_elog(_logger, " *** ${id} sequence not respected on #${block_num} phase ${phase} proposal_id: ${prop_id}", + ("id", _id)("block_num", p->block_num())("phase", p->phase_counter)("prop_id", p->proposal_id)); + } + } + if (!proposal_chain.empty()) { + // commit all ancestor blocks sequentially first (hence the reverse) + for (auto p : boost::adaptors::reverse(proposal_chain)) { // Execute commands [...] - fc_dlog(_logger, " === ${id} committed proposal #${block_num} phase ${phase_counter} block_id : ${block_id} proposal_id : ${proposal_id}", - ("id", _id)("block_num", proposal->block_num())("phase_counter", proposal->phase_counter)("block_id", proposal->block_id)("proposal_id", proposal->proposal_id)); + ; + } + + auto p = proposal_chain.back(); + if (proposal_chain.size() > 1) { + auto last = proposal_chain.front(); + fc_dlog(_logger, " === ${id} committed {num} proposals from #${block_num}:${phase} block_id: ${block_id} " + "proposal_id: ${prop_id} to #${block_num_2}:${phase_2} block_id: ${block_id_2} proposal_id: ${prop_id_2}", + ("id", _id)("block_num", p->block_num())("phase", p->phase_counter)("block_id", p->block_id) + ("prop_id", p->proposal_id)("num", proposal_chain.size())("block_num_2", last->block_num()) + ("phase_2", last->phase_counter)("block_id_2", last->block_id)("prop_id_2", last->proposal_id)); } else { - fc_elog(_logger, " *** ${id} sequence not respected on #${block_num} phase ${phase_counter} proposal_id : ${proposal_id}", - ("id", _id)("block_num", proposal->block_num())("phase_counter", proposal->phase_counter)("proposal_id", proposal->proposal_id)); + fc_dlog(_logger, " === ${id} committed proposal #${block_num} phase ${phase} block_id: ${block_id} proposal_id: ${prop_id}", + ("id", _id)("block_num", p->block_num())("phase", p->phase_counter) + ("block_id", p->block_id)("prop_id", p->proposal_id)); } } } -}} +} From 3c30a3e406b12713a2b872463fb29a02e9183b38 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Wed, 30 Aug 2023 10:36:59 -0400 Subject: [PATCH 111/151] Fix logic mistake in my previous commit --- libraries/hotstuff/qc_chain.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index f6e14c7375..188945551f 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -1086,10 +1086,8 @@ void qc_chain::commit(const hs_proposal_message& initial_proposal) { bool exec_height_check = _b_exec == NULL_PROPOSAL_ID || last_exec_prop->get_height() < p->get_height(); if (exec_height_check) { - if (auto parent = get_proposal(p->parent_id); parent != nullptr) { - proposal_chain.push_back(parent); // add proposal to vector for further processing - p = parent; // process parent proposal next in while loop - } + proposal_chain.push_back(p); // add proposal to vector for further processing + p = get_proposal(p->parent_id); // process parent if non-null } else { fc_elog(_logger, " *** ${id} sequence not respected on #${block_num} phase ${phase} proposal_id: ${prop_id}", ("id", _id)("block_num", p->block_num())("phase", p->phase_counter)("prop_id", p->proposal_id)); From aa4f6e5ffbdca391ab9657db7a64b7436db26834 Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Wed, 30 Aug 2023 19:59:47 -0400 Subject: [PATCH 112/151] Cleanup log messages --- libraries/hotstuff/qc_chain.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 1123950bce..2353e541e5 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -1008,8 +1008,7 @@ void qc_chain::commit(const hs_proposal_message& initial_proposal) { const hs_proposal_message* p = &initial_proposal; while (p) { - fc_tlog(_logger, " === attempting to commit proposal #${block_num} ${prop_id} block_id: ${block_id} " - "phase: ${phase} parent_id: ${parent_id}", + fc_tlog(_logger, " === attempting to commit proposal #${block_num}:${phase} ${prop_id} block_id: ${block_id} parent_id: ${parent_id}", ("block_num", p->block_num())("prop_id", p->proposal_id)("block_id", p->block_id) ("phase", p->phase_counter)("parent_id", p->parent_id)); @@ -1018,8 +1017,7 @@ void qc_chain::commit(const hs_proposal_message& initial_proposal) { "expected hs_proposal ${id} not found", ("id", _b_exec)); if (last_exec_prop != nullptr) { - fc_tlog(_logger, " === _b_exec proposal #${block_num} ${prop_id} block_id: ${block_id} " - "phase: ${phase} parent_id: ${parent_id}", + fc_tlog(_logger, " === _b_exec proposal #${block_num}:${phase} ${prop_id} block_id: ${block_id} parent_id: ${parent_id}", ("block_num", last_exec_prop->block_num())("prop_id", last_exec_prop->proposal_id) ("block_id", last_exec_prop->block_id)("phase", last_exec_prop->phase_counter) ("parent_id", last_exec_prop->parent_id)); @@ -1037,7 +1035,7 @@ void qc_chain::commit(const hs_proposal_message& initial_proposal) { proposal_chain.push_back(p); // add proposal to vector for further processing p = get_proposal(p->parent_id); // process parent if non-null } else { - fc_elog(_logger, " *** ${id} sequence not respected on #${block_num} phase ${phase} proposal_id: ${prop_id}", + fc_elog(_logger, " *** ${id} sequence not respected on #${block_num}:${phase} proposal_id: ${prop_id}", ("id", _id)("block_num", p->block_num())("phase", p->phase_counter)("prop_id", p->proposal_id)); } } @@ -1058,7 +1056,7 @@ void qc_chain::commit(const hs_proposal_message& initial_proposal) { ("prop_id", p->proposal_id)("num", proposal_chain.size())("block_num_2", last->block_num()) ("phase_2", last->phase_counter)("block_id_2", last->block_id)("prop_id_2", last->proposal_id)); } else { - fc_dlog(_logger, " === ${id} committed proposal #${block_num} phase ${phase} block_id: ${block_id} proposal_id: ${prop_id}", + fc_dlog(_logger, " === ${id} committed proposal #${block_num}:${phase} block_id: ${block_id} proposal_id: ${prop_id}", ("id", _id)("block_num", p->block_num())("phase", p->phase_counter) ("block_id", p->block_id)("prop_id", p->proposal_id)); } From 5b28de59eeba8500911ca2b0c3606f5a09320f4e Mon Sep 17 00:00:00 2001 From: greg7mdp Date: Thu, 31 Aug 2023 08:42:37 -0400 Subject: [PATCH 113/151] Watch for infinite loops. --- libraries/hotstuff/qc_chain.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 2353e541e5..2ee77ad3b1 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -1037,6 +1037,7 @@ void qc_chain::commit(const hs_proposal_message& initial_proposal) { } else { fc_elog(_logger, " *** ${id} sequence not respected on #${block_num}:${phase} proposal_id: ${prop_id}", ("id", _id)("block_num", p->block_num())("phase", p->phase_counter)("prop_id", p->proposal_id)); + break; } } From fe6fbc31ac764bb215c2f904cafc94708bfa7e26 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Thu, 31 Aug 2023 18:33:48 +0000 Subject: [PATCH 114/151] Changed bls private, public key / signature encoding from base58 to base64 --- .../libfc/include/fc/crypto/bls_common.hpp | 10 +-- .../include/fc/crypto/bls_private_key.hpp | 2 +- .../include/fc/crypto/bls_public_key.hpp | 2 +- .../libfc/include/fc/crypto/bls_signature.hpp | 2 +- .../libfc/src/crypto/bls_private_key.cpp | 16 ++--- libraries/libfc/src/crypto/bls_public_key.cpp | 16 ++--- libraries/libfc/src/crypto/bls_signature.cpp | 18 ++--- libraries/libfc/test/test_bls.cpp | 66 ++++++++++--------- 8 files changed, 69 insertions(+), 63 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_common.hpp b/libraries/libfc/include/fc/crypto/bls_common.hpp index e071c5d505..7f7b4862be 100644 --- a/libraries/libfc/include/fc/crypto/bls_common.hpp +++ b/libraries/libfc/include/fc/crypto/bls_common.hpp @@ -4,17 +4,17 @@ namespace fc::crypto::blslib { template - static Container serialize_base58(const std::string& data_str) + static Container serialize_base64(const std::string& data_str) { using wrapper = checksummed_data; wrapper wrapped; - auto bin = fc::from_base58(data_str); + auto bin = fc::base64_decode(data_str); fc::datastream unpacker(bin.data(), bin.size()); fc::raw::unpack(unpacker, wrapped); - FC_ASSERT(!unpacker.remaining(), "decoded base58 length too long"); + FC_ASSERT(!unpacker.remaining(), "decoded base64 length too long"); auto checksum = wrapper::calculate_checksum(wrapped.data, nullptr); FC_ASSERT(checksum == wrapped.check); @@ -22,7 +22,7 @@ namespace fc::crypto::blslib { } template - static std::string deserialize_base58( Container data, const yield_function_t& yield) { + static std::string deserialize_base64( Container data, const yield_function_t& yield) { using wrapper = checksummed_data; @@ -34,7 +34,7 @@ namespace fc::crypto::blslib { yield(); auto packed = raw::pack( wrapped ); yield(); - auto data_str = to_base58( packed.data(), packed.size(), yield ); + auto data_str = fc::base64_encode( packed.data(), packed.size()); yield(); return data_str; diff --git a/libraries/libfc/include/fc/crypto/bls_private_key.hpp b/libraries/libfc/include/fc/crypto/bls_private_key.hpp index deff417e85..f4d3b3e3ca 100644 --- a/libraries/libfc/include/fc/crypto/bls_private_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_private_key.hpp @@ -20,7 +20,7 @@ namespace fc::crypto::blslib { explicit bls_private_key(const std::vector& seed ) { _sk = bls12_381::secret_key(seed); } - explicit bls_private_key(const std::string& base58str); + explicit bls_private_key(const std::string& base64str); bls_private_key& operator=( const bls_private_key& ) = default; diff --git a/libraries/libfc/include/fc/crypto/bls_public_key.hpp b/libraries/libfc/include/fc/crypto/bls_public_key.hpp index b2d552888d..baaab65273 100644 --- a/libraries/libfc/include/fc/crypto/bls_public_key.hpp +++ b/libraries/libfc/include/fc/crypto/bls_public_key.hpp @@ -18,7 +18,7 @@ namespace fc::crypto::blslib { bls_public_key( bls_public_key&& ) = default; bls_public_key( const bls_public_key& ) = default; explicit bls_public_key( const bls12_381::g1& pkey ) {_pkey = pkey;} - explicit bls_public_key(const std::string& base58str); + explicit bls_public_key(const std::string& base64str); bls_public_key& operator=(const bls_public_key&) = default; std::string to_string(const yield_function_t& yield = yield_function_t()) const; diff --git a/libraries/libfc/include/fc/crypto/bls_signature.hpp b/libraries/libfc/include/fc/crypto/bls_signature.hpp index ef2b80b725..e87f2f6253 100644 --- a/libraries/libfc/include/fc/crypto/bls_signature.hpp +++ b/libraries/libfc/include/fc/crypto/bls_signature.hpp @@ -22,7 +22,7 @@ namespace fc::crypto::blslib { bls_signature( bls_signature&& ) = default; bls_signature( const bls_signature& ) = default; explicit bls_signature( const bls12_381::g2& sig ){_sig = sig;} - explicit bls_signature(const std::string& base58str); + explicit bls_signature(const std::string& base64str); bls_signature& operator= (const bls_signature& ) = default; std::string to_string(const yield_function_t& yield = yield_function_t()) const; diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index 1380462d05..2a9c16cdf0 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -25,26 +25,26 @@ namespace fc::crypto::blslib { return bls_private_key(v); } - static std::array priv_parse_base58(const std::string& base58str) + static std::array priv_parse_base64(const std::string& base64str) { auto res = std::mismatch(config::bls_private_key_prefix.begin(), config::bls_private_key_prefix.end(), - base58str.begin()); - FC_ASSERT(res.first == config::bls_private_key_prefix.end(), "BLS Private Key has invalid format : ${str}", ("str", base58str)); + base64str.begin()); + FC_ASSERT(res.first == config::bls_private_key_prefix.end(), "BLS Private Key has invalid format : ${str}", ("str", base64str)); - auto data_str = base58str.substr(config::bls_private_key_prefix.size()); + auto data_str = base64str.substr(config::bls_private_key_prefix.size()); - std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); + std::array bytes = fc::crypto::blslib::serialize_base64>(data_str); return bytes; } - bls_private_key::bls_private_key(const std::string& base58str) - :_sk(priv_parse_base58(base58str)) + bls_private_key::bls_private_key(const std::string& base64str) + :_sk(priv_parse_base64(base64str)) {} std::string bls_private_key::to_string(const yield_function_t& yield) const { - std::string data_str = fc::crypto::blslib::deserialize_base58>(_sk, yield); + std::string data_str = fc::crypto::blslib::deserialize_base64>(_sk, yield); return config::bls_private_key_prefix + data_str; } diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 9da57e4f7a..6777afb477 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -5,30 +5,30 @@ namespace fc::crypto::blslib { - static bls12_381::g1 pub_parse_base58(const std::string& base58str) + static bls12_381::g1 pub_parse_base64(const std::string& base64str) { auto res = std::mismatch(config::bls_public_key_prefix.begin(), config::bls_public_key_prefix.end(), - base58str.begin()); - FC_ASSERT(res.first == config::bls_public_key_prefix.end(), "BLS Public Key has invalid format : ${str}", ("str", base58str)); + base64str.begin()); + FC_ASSERT(res.first == config::bls_public_key_prefix.end(), "BLS Public Key has invalid format : ${str}", ("str", base64str)); - auto data_str = base58str.substr(config::bls_public_key_prefix.size()); + auto data_str = base64str.substr(config::bls_public_key_prefix.size()); - std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); + std::array bytes = fc::crypto::blslib::serialize_base64>(data_str); std::optional g1 = bls12_381::g1::fromCompressedBytesBE(bytes); FC_ASSERT(g1); return *g1; } - bls_public_key::bls_public_key(const std::string& base58str) - :_pkey(pub_parse_base58(base58str)) + bls_public_key::bls_public_key(const std::string& base64str) + :_pkey(pub_parse_base64(base64str)) {} std::string bls_public_key::to_string(const yield_function_t& yield)const { std::array bytes = _pkey.toCompressedBytesBE(); - std::string data_str = fc::crypto::blslib::deserialize_base58>(bytes, yield); + std::string data_str = fc::crypto::blslib::deserialize_base64>(bytes, yield); return config::bls_public_key_prefix + data_str; diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index cb9df7298c..4fdff74174 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -5,27 +5,27 @@ namespace fc::crypto::blslib { - static bls12_381::g2 sig_parse_base58(const std::string& base58str) + static bls12_381::g2 sig_parse_base64(const std::string& base64str) { try { auto res = std::mismatch(config::bls_signature_prefix.begin(), config::bls_signature_prefix.end(), - base58str.begin()); - FC_ASSERT(res.first == config::bls_signature_prefix.end(), "BLS Signature has invalid format : ${str}", ("str", base58str)); + base64str.begin()); + FC_ASSERT(res.first == config::bls_signature_prefix.end(), "BLS Signature has invalid format : ${str}", ("str", base64str)); - auto data_str = base58str.substr(config::bls_signature_prefix.size()); + auto data_str = base64str.substr(config::bls_signature_prefix.size()); - std::array bytes = fc::crypto::blslib::serialize_base58>(data_str); + std::array bytes = fc::crypto::blslib::serialize_base64>(data_str); std::optional g2 = bls12_381::g2::fromCompressedBytesBE(bytes); FC_ASSERT(g2); return *g2; - } FC_RETHROW_EXCEPTIONS( warn, "error parsing bls_signature", ("str", base58str ) ) + } FC_RETHROW_EXCEPTIONS( warn, "error parsing bls_signature", ("str", base64str ) ) } - bls_signature::bls_signature(const std::string& base58str) - :_sig(sig_parse_base58(base58str)) + bls_signature::bls_signature(const std::string& base64str) + :_sig(sig_parse_base64(base64str)) {} std::string bls_signature::to_string(const yield_function_t& yield) const @@ -33,7 +33,7 @@ namespace fc::crypto::blslib { std::array bytes = _sig.toCompressedBytesBE(); - std::string data_str = fc::crypto::blslib::deserialize_base58>(bytes, yield); + std::string data_str = fc::crypto::blslib::deserialize_base64>(bytes, yield); return config::bls_signature_prefix + data_str; diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 9aa9c27f08..ca5767da34 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -245,6 +245,8 @@ BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { std::string priv_str = sk.to_string(); + std::cout << priv_str << "\n"; + bool ok2 = bls_private_key(priv_str).to_string() == priv_str; bls_public_key pk = sk.get_public_key(); @@ -253,6 +255,8 @@ BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { std::string pub_str = pk.to_string(); + std::cout << pub_str << "\n"; + bool ok4 = bls_public_key(pub_str).to_string() == pub_str; bls_signature sig = sk.sign(message_1); @@ -261,6 +265,8 @@ BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { std::string sig_str = sig.to_string(); + std::cout << sig_str << "\n"; + bool ok6 = bls_signature(sig_str).to_string() == sig_str; bool ok7 = verify(pk, message_1, bls_signature(sig.to_string())); @@ -280,48 +286,48 @@ BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { BOOST_AUTO_TEST_CASE(bls_prefix_encoding_check) try { //test no_throw for correctly encoded keys - BOOST_CHECK_NO_THROW(bls_private_key("PVT_BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG")); - BOOST_CHECK_NO_THROW(bls_public_key("PUB_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu")); - BOOST_CHECK_NO_THROW(bls_signature("SIG_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o")); + BOOST_CHECK_NO_THROW(bls_private_key("PVT_BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x")); + BOOST_CHECK_NO_THROW(bls_public_key("PUB_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA==")); + BOOST_CHECK_NO_THROW(bls_signature("SIG_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g==")); //test no pivot delimiter - BOOST_CHECK_THROW(bls_private_key("PVTBLSM6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUBBLSZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("SIGBLS7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("PVTBLSLaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUBBLShiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIGBLSqn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); //test first prefix validation - BOOST_CHECK_THROW(bls_private_key("XYZ_BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("XYZ_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("XYZ_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("XYZ_BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("XYZ_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("XYZ_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); //test second prefix validation - BOOST_CHECK_THROW(bls_private_key("PVT_XYZ_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_XYZ_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("SIG_XYZ_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("PVT_XYZ_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_XYZ_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_XYZ_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); //test missing prefix - BOOST_CHECK_THROW(bls_private_key("M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); //test incomplete prefix - BOOST_CHECK_THROW(bls_private_key("PVT_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("PUB_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); - BOOST_CHECK_THROW(bls_private_key("BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("PVT_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); //test invalid data / invalid checksum - BOOST_CHECK_THROW(bls_private_key("PVT_BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcH"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsv"), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("PUB_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3p"), fc::assert_exception); - BOOST_CHECK_THROW(bls_private_key("PVT_BLS_N6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_BLS_ACYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("PUB_BLS_6dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); - BOOST_CHECK_THROW(bls_private_key("PVT_BLS_M6m7EUvzEbQErhkKUrsA96VGqdM3R3MTDszXnywcwPCt3XAcG"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtE3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("PUB_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHug1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("PVT_BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+y"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFBA=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS8g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("PVT_BLS_LaNRcYuQxSm/tRrMofQduPb5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpnwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqQ8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_private_key("PVT_BLS_MaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_BLS_iiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_BLS_rn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); } FC_LOG_AND_RETHROW(); From 361c1b2963305ea86c3b2eb2143b03f1cdda6f87 Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Thu, 31 Aug 2023 20:07:23 +0000 Subject: [PATCH 115/151] Removed unnecessary yield function parameter, corrected semantic inversion of serialize / deserialize --- libraries/libfc/include/fc/crypto/bls_common.hpp | 10 +++------- libraries/libfc/src/crypto/bls_private_key.cpp | 4 ++-- libraries/libfc/src/crypto/bls_public_key.cpp | 4 ++-- libraries/libfc/src/crypto/bls_signature.cpp | 4 ++-- libraries/libfc/test/test_bls.cpp | 6 ------ 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/libraries/libfc/include/fc/crypto/bls_common.hpp b/libraries/libfc/include/fc/crypto/bls_common.hpp index 7f7b4862be..86e54f1e1d 100644 --- a/libraries/libfc/include/fc/crypto/bls_common.hpp +++ b/libraries/libfc/include/fc/crypto/bls_common.hpp @@ -4,7 +4,7 @@ namespace fc::crypto::blslib { template - static Container serialize_base64(const std::string& data_str) + static Container deserialize_base64(const std::string& data_str) { using wrapper = checksummed_data; @@ -22,21 +22,17 @@ namespace fc::crypto::blslib { } template - static std::string deserialize_base64( Container data, const yield_function_t& yield) { + static std::string serialize_base64( Container data) { using wrapper = checksummed_data; wrapper wrapped; wrapped.data = data; - yield(); wrapped.check = wrapper::calculate_checksum(wrapped.data, nullptr); - yield(); auto packed = raw::pack( wrapped ); - yield(); auto data_str = fc::base64_encode( packed.data(), packed.size()); - yield(); - + return data_str; } diff --git a/libraries/libfc/src/crypto/bls_private_key.cpp b/libraries/libfc/src/crypto/bls_private_key.cpp index 2a9c16cdf0..ced3d429da 100644 --- a/libraries/libfc/src/crypto/bls_private_key.cpp +++ b/libraries/libfc/src/crypto/bls_private_key.cpp @@ -33,7 +33,7 @@ namespace fc::crypto::blslib { auto data_str = base64str.substr(config::bls_private_key_prefix.size()); - std::array bytes = fc::crypto::blslib::serialize_base64>(data_str); + std::array bytes = fc::crypto::blslib::deserialize_base64>(data_str); return bytes; } @@ -44,7 +44,7 @@ namespace fc::crypto::blslib { std::string bls_private_key::to_string(const yield_function_t& yield) const { - std::string data_str = fc::crypto::blslib::deserialize_base64>(_sk, yield); + std::string data_str = fc::crypto::blslib::serialize_base64>(_sk); return config::bls_private_key_prefix + data_str; } diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 6777afb477..f137a1cce6 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -13,7 +13,7 @@ namespace fc::crypto::blslib { auto data_str = base64str.substr(config::bls_public_key_prefix.size()); - std::array bytes = fc::crypto::blslib::serialize_base64>(data_str); + std::array bytes = fc::crypto::blslib::deserialize_base64>(data_str); std::optional g1 = bls12_381::g1::fromCompressedBytesBE(bytes); FC_ASSERT(g1); @@ -28,7 +28,7 @@ namespace fc::crypto::blslib { std::array bytes = _pkey.toCompressedBytesBE(); - std::string data_str = fc::crypto::blslib::deserialize_base64>(bytes, yield); + std::string data_str = fc::crypto::blslib::serialize_base64>(bytes); return config::bls_public_key_prefix + data_str; diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 4fdff74174..bab437b521 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -15,7 +15,7 @@ namespace fc::crypto::blslib { auto data_str = base64str.substr(config::bls_signature_prefix.size()); - std::array bytes = fc::crypto::blslib::serialize_base64>(data_str); + std::array bytes = fc::crypto::blslib::deserialize_base64>(data_str); std::optional g2 = bls12_381::g2::fromCompressedBytesBE(bytes); FC_ASSERT(g2); @@ -33,7 +33,7 @@ namespace fc::crypto::blslib { std::array bytes = _sig.toCompressedBytesBE(); - std::string data_str = fc::crypto::blslib::deserialize_base64>(bytes, yield); + std::string data_str = fc::crypto::blslib::serialize_base64>(bytes); return config::bls_signature_prefix + data_str; diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index ca5767da34..790e440d90 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -245,8 +245,6 @@ BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { std::string priv_str = sk.to_string(); - std::cout << priv_str << "\n"; - bool ok2 = bls_private_key(priv_str).to_string() == priv_str; bls_public_key pk = sk.get_public_key(); @@ -255,8 +253,6 @@ BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { std::string pub_str = pk.to_string(); - std::cout << pub_str << "\n"; - bool ok4 = bls_public_key(pub_str).to_string() == pub_str; bls_signature sig = sk.sign(message_1); @@ -265,8 +261,6 @@ BOOST_AUTO_TEST_CASE(bls_binary_keys_encoding_check) try { std::string sig_str = sig.to_string(); - std::cout << sig_str << "\n"; - bool ok6 = bls_signature(sig_str).to_string() == sig_str; bool ok7 = verify(pk, message_1, bls_signature(sig.to_string())); From 2c478df912e615a3084e6bfef38d6caede243432 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 31 Aug 2023 16:41:28 -0500 Subject: [PATCH 116/151] GH-1523 Remove unneeded uniqueness check for description. Add 256 limit to description. --- libraries/chain/webassembly/privileged.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index dc3992709f..5b036e832b 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -156,24 +157,21 @@ namespace eosio { namespace chain { namespace webassembly { fc::datastream ds( packed_finalizer_set.data(), packed_finalizer_set.size() ); finalizer_set finset; fc::raw::unpack(ds, finset); - vector & finalizers = finset.finalizers; + vector& finalizers = 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; uint64_t f_weight_sum = 0; for (const auto& f: finalizers) { f_weight_sum += f.fweight; unique_finalizer_keys.insert(f.public_key); - unique_finalizers.insert(f.description); + EOS_ASSERT( f.description.size() <= 256, wasm_execution_error, "Finalizer description greater than 256" ); } - 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" ); From c6aa35832a8e84381f35b9f88a0547d9c3d12437 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 31 Aug 2023 16:42:43 -0500 Subject: [PATCH 117/151] GH-1523 Add hs_finalizer_set_extension and refactor to prevent inclusion of bls12-381 headers in header files. --- libraries/chain/CMakeLists.txt | 1 + libraries/chain/finalizer_set.cpp | 27 +++++++ .../eosio/chain/finalizer_authority.hpp | 19 +++++ .../include/eosio/chain/finalizer_set.hpp | 70 ++++++++----------- 4 files changed, 77 insertions(+), 40 deletions(-) create mode 100644 libraries/chain/finalizer_set.cpp create mode 100644 libraries/chain/include/eosio/chain/finalizer_authority.hpp 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/finalizer_set.cpp b/libraries/chain/finalizer_set.cpp new file mode 100644 index 0000000000..293b7523fe --- /dev/null +++ b/libraries/chain/finalizer_set.cpp @@ -0,0 +1,27 @@ +#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&&) = default; + + finalizer_set& finalizer_set::operator=(const finalizer_set&) = default; + finalizer_set& finalizer_set::operator=(finalizer_set&&) = default; + + auto finalizer_set::operator<=>(const finalizer_set&) const = default; + + + hs_finalizer_set_extension::hs_finalizer_set_extension(const finalizer_set& s) + : finalizer_set(s) {} + +} /// eosio::chain 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..b3399f4228 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -1,59 +1,49 @@ #pragma once -#include #include -#include -#include -#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; - - 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); - } - }; + struct finalizer_authority; struct finalizer_set { - finalizer_set() = default; + finalizer_set(); + ~finalizer_set(); + + finalizer_set(const finalizer_set&); + finalizer_set(finalizer_set&&); - finalizer_set( uint32_t version, uint64_t fthreshold, std::initializer_list finalizers ) - :version(version) - ,fthreshold(fthreshold) - ,finalizers(finalizers) - {} + finalizer_set& operator=(const finalizer_set&); + finalizer_set& operator=(finalizer_set&&); 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); - } + auto operator<=>(const finalizer_set&) const; + }; + + 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; } + + hs_finalizer_set_extension() = default; + hs_finalizer_set_extension(const hs_finalizer_set_extension&) = default; + hs_finalizer_set_extension( hs_finalizer_set_extension&& ) = default; + + hs_finalizer_set_extension& operator=(const hs_finalizer_set_extension&) = default; + hs_finalizer_set_extension& operator=(hs_finalizer_set_extension&&) = default; + + hs_finalizer_set_extension(const finalizer_set& s); }; } /// eosio::chain -FC_REFLECT( eosio::chain::finalizer_authority, (description)(fweight)(public_key) ) FC_REFLECT( eosio::chain::finalizer_set, (version)(fthreshold)(finalizers) ) +FC_REFLECT_DERIVED( eosio::chain::hs_finalizer_set_extension, (eosio::chain::finalizer_set), ) \ No newline at end of file From ef8069db18ed830b68dce54406c5a1e45eef22a5 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 31 Aug 2023 18:36:01 -0500 Subject: [PATCH 118/151] GH-1523 Use 65536 for max_finalizers and 256 for max finalizer description. Remove generation from finalizer_set used by CDT/ABI. --- libraries/chain/controller.cpp | 1 + libraries/chain/include/eosio/chain/config.hpp | 3 ++- libraries/chain/include/eosio/chain/finalizer_set.hpp | 8 ++++---- libraries/chain/webassembly/privileged.cpp | 11 ++++++++--- 4 files changed, 15 insertions(+), 8 deletions(-) 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/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index c3f91d9cbe..a841c53f7a 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 = 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_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index b3399f4228..cfc8207ac8 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -16,9 +16,9 @@ namespace eosio::chain { finalizer_set& operator=(const finalizer_set&); finalizer_set& operator=(finalizer_set&&); - uint32_t version = 0; ///< sequentially incrementing version number - uint64_t fthreshold = 0; // vote fweight threshold to finalize blocks - vector finalizers; // Instant Finality voter set + 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 auto operator<=>(const finalizer_set&) const; }; @@ -45,5 +45,5 @@ namespace eosio::chain { } /// eosio::chain -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 5b036e832b..9872905313 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -156,10 +156,15 @@ namespace eosio { namespace chain { namespace webassembly { EOS_ASSERT(!context.trx_context.is_read_only(), wasm_execution_error, "set_proposed_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); + // contract finalizer_set does not include uint32_t generation + // struct abi_finalizer_set { + // uint64_t fthreshold + // vector finalizers; } + fc::raw::unpack(ds, finset.fthreshold); + fc::raw::unpack(ds, finset.finalizers); + vector& finalizers = 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" ); @@ -169,7 +174,7 @@ namespace eosio { namespace chain { namespace webassembly { for (const auto& f: finalizers) { f_weight_sum += f.fweight; unique_finalizer_keys.insert(f.public_key); - EOS_ASSERT( f.description.size() <= 256, wasm_execution_error, "Finalizer description greater than 256" ); + EOS_ASSERT( f.description.size() <= config::max_finalizer_description, wasm_execution_error, "Finalizer description greater than 256" ); } EOS_ASSERT( finalizers.size() == unique_finalizer_keys.size(), wasm_execution_error, "Duplicate finalizer bls key in finalizer set" ); From bbc04936d5af3675d2f5bbe9777f894588e2f76f Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 1 Sep 2023 07:59:14 -0500 Subject: [PATCH 119/151] Minor cleanup --- libraries/chain/webassembly/privileged.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index 9872905313..70720a5a3b 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -153,7 +153,7 @@ namespace eosio { namespace chain { namespace webassembly { } 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; // contract finalizer_set does not include uint32_t generation @@ -172,9 +172,9 @@ namespace eosio { namespace chain { namespace webassembly { uint64_t f_weight_sum = 0; for (const auto& f: finalizers) { + EOS_ASSERT( f.description.size() <= config::max_finalizer_description, wasm_execution_error, "Finalizer description greater than 256" ); f_weight_sum += f.fweight; unique_finalizer_keys.insert(f.public_key); - EOS_ASSERT( f.description.size() <= config::max_finalizer_description, wasm_execution_error, "Finalizer description greater than 256" ); } EOS_ASSERT( finalizers.size() == unique_finalizer_keys.size(), wasm_execution_error, "Duplicate finalizer bls key in finalizer set" ); From 48a268b4a18ba4aed1cfe98058b69a3dbd844dd1 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 1 Sep 2023 10:16:30 -0500 Subject: [PATCH 120/151] GH-1523 Change contract bls_public_key format to JacobianLE --- libraries/chain/webassembly/privileged.cpp | 32 ++++++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index 70720a5a3b..25d00e1440 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -152,18 +152,24 @@ 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; + vector finalizers; + }; + void interface::set_finalizers(span packed_finalizer_set) { 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; - // contract finalizer_set does not include uint32_t generation - // struct abi_finalizer_set { - // uint64_t fthreshold - // vector finalizers; } - fc::raw::unpack(ds, finset.fthreshold); - fc::raw::unpack(ds, finset.finalizers); + abi_finalizer_set abi_finset; + fc::raw::unpack(ds, abi_finset); - vector& finalizers = finset.finalizers; + vector& finalizers = abi_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" ); @@ -171,10 +177,15 @@ namespace eosio { namespace chain { namespace webassembly { 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, wasm_execution_error, "Finalizer description greater than 256" ); f_weight_sum += f.fweight; - unique_finalizer_keys.insert(f.public_key); + 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{*pk}}); + unique_finalizer_keys.insert(finset.finalizers.back().public_key); } EOS_ASSERT( finalizers.size() == unique_finalizer_keys.size(), wasm_execution_error, "Duplicate finalizer bls key in finalizer set" ); @@ -257,3 +268,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 From f24626a389413784c0a772953f1c17bd847ef59a Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 1 Sep 2023 10:43:36 -0500 Subject: [PATCH 121/151] GH-1523 bls_public_key has explicit constructor --- libraries/chain/webassembly/privileged.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index 25d00e1440..c9189ed6fc 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -184,7 +184,7 @@ namespace eosio { namespace chain { namespace webassembly { f_weight_sum += f.fweight; 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{*pk}}); + 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(finset.finalizers.back().public_key); } From decb6c27713ccfd168d700151a2ae852cd93c56e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 1 Sep 2023 10:58:31 -0500 Subject: [PATCH 122/151] GH-1523 Minor cleanup --- libraries/chain/finalizer_set.cpp | 8 ++----- .../chain/include/eosio/chain/config.hpp | 2 +- .../include/eosio/chain/finalizer_set.hpp | 22 +++++-------------- libraries/chain/webassembly/privileged.cpp | 9 ++++---- 4 files changed, 14 insertions(+), 27 deletions(-) diff --git a/libraries/chain/finalizer_set.cpp b/libraries/chain/finalizer_set.cpp index 293b7523fe..6fa56a2b0a 100644 --- a/libraries/chain/finalizer_set.cpp +++ b/libraries/chain/finalizer_set.cpp @@ -13,15 +13,11 @@ namespace eosio::chain { finalizer_set::~finalizer_set() = default; finalizer_set::finalizer_set(const finalizer_set&) = default; - finalizer_set::finalizer_set(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&&) = default; + finalizer_set& finalizer_set::operator=(finalizer_set&&) noexcept = default; auto finalizer_set::operator<=>(const finalizer_set&) const = default; - - hs_finalizer_set_extension::hs_finalizer_set_extension(const finalizer_set& s) - : finalizer_set(s) {} - } /// eosio::chain diff --git a/libraries/chain/include/eosio/chain/config.hpp b/libraries/chain/include/eosio/chain/config.hpp index a841c53f7a..d46df346e5 100644 --- a/libraries/chain/include/eosio/chain/config.hpp +++ b/libraries/chain/include/eosio/chain/config.hpp @@ -134,7 +134,7 @@ static_assert(maximum_tracked_dpos_confirmations >= ((max_producers * 2 / 3) + 1 * Maximum number of finalizers in the finalizer set */ const static size_t max_finalizers = 64*1024; -const static size_t max_finalizer_description = 256; +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_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index cfc8207ac8..ced75ca27c 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -11,16 +11,16 @@ namespace eosio::chain { ~finalizer_set(); finalizer_set(const finalizer_set&); - finalizer_set(finalizer_set&&); + finalizer_set(finalizer_set&&) noexcept; finalizer_set& operator=(const finalizer_set&); - finalizer_set& operator=(finalizer_set&&); - - 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 + 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 finalizers; ///< Instant Finality voter set }; using finalizer_set_ptr = std::shared_ptr; @@ -29,18 +29,8 @@ namespace eosio::chain { * 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; } - - hs_finalizer_set_extension() = default; - hs_finalizer_set_extension(const hs_finalizer_set_extension&) = default; - hs_finalizer_set_extension( hs_finalizer_set_extension&& ) = default; - - hs_finalizer_set_extension& operator=(const hs_finalizer_set_extension&) = default; - hs_finalizer_set_extension& operator=(hs_finalizer_set_extension&&) = default; - - hs_finalizer_set_extension(const finalizer_set& s); }; } /// eosio::chain diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index c9189ed6fc..52dd87cbcf 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -159,8 +159,8 @@ namespace eosio { namespace chain { namespace webassembly { std::array public_key_g1_jacobian; }; struct abi_finalizer_set { - uint64_t fthreshold = 0; - vector finalizers; + uint64_t fthreshold = 0; + std::vector finalizers; }; void interface::set_finalizers(span packed_finalizer_set) { @@ -169,7 +169,7 @@ namespace eosio { namespace chain { namespace webassembly { abi_finalizer_set abi_finset; fc::raw::unpack(ds, abi_finset); - vector& finalizers = abi_finset.finalizers; + std::vector& finalizers = abi_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" ); @@ -180,7 +180,8 @@ namespace eosio { namespace chain { namespace webassembly { finalizer_set finset; finset.fthreshold = abi_finset.fthreshold; for (const auto& f: finalizers) { - EOS_ASSERT( f.description.size() <= config::max_finalizer_description, wasm_execution_error, "Finalizer description greater than 256" ); + 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 pk = bls12_381::g1::fromJacobianBytesLE(f.public_key_g1_jacobian); EOS_ASSERT( pk, wasm_execution_error, "Invalid public key for: ${d}", ("d", f.description) ); From 060b5bad5a0d908799cde57b5d072b90d2fdc6df Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 1 Sep 2023 12:33:57 -0500 Subject: [PATCH 123/151] GH-1523 Minor cleanup --- libraries/chain/webassembly/privileged.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index 52dd87cbcf..ec704da324 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -174,7 +174,7 @@ namespace eosio { namespace chain { namespace webassembly { 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; + std::set unique_finalizer_keys; uint64_t f_weight_sum = 0; finalizer_set finset; @@ -185,8 +185,10 @@ namespace eosio { namespace chain { namespace webassembly { f_weight_sum += f.fweight; 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(finset.finalizers.back().public_key); + 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_finalizer_keys.size(), wasm_execution_error, "Duplicate finalizer bls key in finalizer set" ); From 07e05f00c1eb4476c3be5d692401a186c2ac87d2 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 1 Sep 2023 15:06:13 -0500 Subject: [PATCH 124/151] GH-1523 WIP: adding proposed finalizer_set to block_header_state and block_header extension. --- libraries/chain/block_header.cpp | 25 ++++++++++++++ libraries/chain/block_header_state.cpp | 1 + libraries/chain/controller.cpp | 30 ++++++++++------ .../include/eosio/chain/abi_serializer.hpp | 7 ++++ .../include/eosio/chain/block_header.hpp | 6 +++- .../eosio/chain/block_header_state.hpp | 5 ++- .../chain/include/eosio/chain/controller.hpp | 4 +-- libraries/chain/webassembly/privileged.cpp | 2 +- libraries/hotstuff/chain_pacemaker.cpp | 34 ++++++++++--------- .../eosio/hotstuff/chain_pacemaker.hpp | 4 ++- 10 files changed, 86 insertions(+), 32 deletions(-) diff --git a/libraries/chain/block_header.cpp b/libraries/chain/block_header.cpp index eef0f5bee3..9a614173af 100644 --- a/libraries/chain/block_header.cpp +++ b/libraries/chain/block_header.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -64,4 +65,28 @@ namespace eosio { namespace chain { return results; } + std::optional 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( 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 {}; + } + } } diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index b7cd3036ac..e809e6d393 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -65,6 +65,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 ); diff --git a/libraries/chain/controller.cpp b/libraries/chain/controller.cpp index 1fa7cbb1aa..888d8dc379 100644 --- a/libraries/chain/controller.cpp +++ b/libraries/chain/controller.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -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: @@ -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(pending->_block_stage); + + bb._pending_block_header_state.proposed_finalizer_set.emplace(fin_set); } /** @@ -3290,12 +3304,8 @@ int64_t controller::set_proposed_producers( vector 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 { diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index 3cad62bcf5..a9eb4c3b75 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -676,6 +676,13 @@ namespace impl { std::get(header_exts.lower_bound(producer_schedule_change_extension::extension_id())->second); mvo("new_producer_schedule", new_producer_schedule); } + if (header_exts.count(hs_finalizer_set_extension::extension_id())) { + // TODO: Will not compile without including finalizer_authority.hpp which includes bls12-381. + // Should we store the bls_public_key in compressed form? +// const auto& finalizer_set_extension = +// std::get(header_exts.lower_bound(hs_finalizer_set_extension::extension_id())->second); +// mvo("proposed_finalizer_set", finalizer_set_extension); + } mvo("producer_signature", block.producer_signature); add(mvo, "transactions", block.transactions, resolver, ctx); diff --git a/libraries/chain/include/eosio/chain/block_header.hpp b/libraries/chain/include/eosio/chain/block_header.hpp index f245841777..8bb7976b76 100644 --- a/libraries/chain/include/eosio/chain/block_header.hpp +++ b/libraries/chain/include/eosio/chain/block_header.hpp @@ -2,7 +2,9 @@ #include #include #include +#include +#include #include namespace eosio { namespace chain { @@ -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; @@ -68,6 +71,7 @@ namespace eosio { namespace chain { static uint32_t num_from_id(const block_id_type& id); flat_multimap validate_and_extract_header_extensions()const; + std::optional extract_header_extension(uint16_t extension_id)const; }; diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 5b4d64ce48..060c1ee943 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -2,6 +2,7 @@ #include #include #include +#include #include #include @@ -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 producer_to_last_produced; flat_map producer_to_last_implied_irb; @@ -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 proposed_finalizer_set; // set by set_finalizer host function bool was_pending_promoted = false; block_id_type previous; account_name producer; @@ -143,7 +146,6 @@ struct block_header_state : public detail::block_header_state_common { const vector& )>& 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; @@ -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) diff --git a/libraries/chain/include/eosio/chain/controller.hpp b/libraries/chain/include/eosio/chain/controller.hpp index 7f7dede8f0..5c16868f97 100644 --- a/libraries/chain/include/eosio/chain/controller.hpp +++ b/libraries/chain/include/eosio/chain/controller.hpp @@ -293,8 +293,8 @@ namespace eosio { namespace chain { int64_t set_proposed_producers( vector 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; diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index ec704da324..5aa052e4e8 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -194,7 +194,7 @@ namespace eosio { namespace chain { namespace webassembly { 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 packed_blockchain_parameters ) const { diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 1e55bda11a..3110458214 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -1,4 +1,5 @@ #include +#include #include // comment this out to remove the core profiler @@ -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(); } @@ -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 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(*ext)); + } + } } name chain_pacemaker::get_proposer() { @@ -246,21 +259,10 @@ namespace eosio { namespace hotstuff { std::vector 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(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index a16a583a7f..70320adc11 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -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 @@ -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 bcast_hs_message; From b6e8da9d13c74750553e45b5eafa680ce2827cc0 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 1 Sep 2023 19:01:05 -0500 Subject: [PATCH 125/151] GH-1523 to/from variant tests --- libraries/libfc/test/test_bls.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 9aa9c27f08..35175cd954 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -2,13 +2,14 @@ #include - #include #include #include #include #include +#include +#include using std::cout; @@ -325,4 +326,24 @@ BOOST_AUTO_TEST_CASE(bls_prefix_encoding_check) try { } FC_LOG_AND_RETHROW(); +BOOST_AUTO_TEST_CASE(bls_variant) try { + bls_private_key prk("PVT_BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"); + bls_public_key pk("PUB_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"); + bls_signature sig("SIG_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"); + + fc::variant v; + std::string s; + v = prk; + s = fc::json::to_string(v, {}); + BOOST_CHECK_EQUAL(s, "\"" + prk.to_string({}) + "\""); + + v = pk; + s = fc::json::to_string(v, {}); + BOOST_CHECK_EQUAL(s, "\"" + pk.to_string({}) + "\""); + + v = sig; + s = fc::json::to_string(v, {}); + BOOST_CHECK_EQUAL(s, "\"" + sig.to_string({}) + "\""); +} FC_LOG_AND_RETHROW(); + BOOST_AUTO_TEST_SUITE_END() From 9ef88bbefed69e38a1dc57ffb08118bb355d90dd Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Fri, 1 Sep 2023 19:01:58 -0500 Subject: [PATCH 126/151] GH-1523 Add abi_serializer of hs_finalizer_set_extension --- libraries/chain/abi_serializer.cpp | 9 +++++++++ libraries/chain/include/eosio/chain/abi_serializer.hpp | 10 +++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/libraries/chain/abi_serializer.cpp b/libraries/chain/abi_serializer.cpp index 0e6232b8af..ab6546f4aa 100644 --- a/libraries/chain/abi_serializer.cpp +++ b/libraries/chain/abi_serializer.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -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& header_exts ) { + if (header_exts.count(hs_finalizer_set_extension::extension_id())) { + const auto& finalizer_set_extension = + std::get(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; diff --git a/libraries/chain/include/eosio/chain/abi_serializer.hpp b/libraries/chain/include/eosio/chain/abi_serializer.hpp index a9eb4c3b75..d257ec725f 100644 --- a/libraries/chain/include/eosio/chain/abi_serializer.hpp +++ b/libraries/chain/include/eosio/chain/abi_serializer.hpp @@ -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& header_exts ); + /** * overload of to_variant_object for signed_block * @@ -676,13 +678,7 @@ namespace impl { std::get(header_exts.lower_bound(producer_schedule_change_extension::extension_id())->second); mvo("new_producer_schedule", new_producer_schedule); } - if (header_exts.count(hs_finalizer_set_extension::extension_id())) { - // TODO: Will not compile without including finalizer_authority.hpp which includes bls12-381. - // Should we store the bls_public_key in compressed form? -// const auto& finalizer_set_extension = -// std::get(header_exts.lower_bound(hs_finalizer_set_extension::extension_id())->second); -// mvo("proposed_finalizer_set", finalizer_set_extension); - } + add_block_header_finalizer_set_extension(mvo, header_exts); mvo("producer_signature", block.producer_signature); add(mvo, "transactions", block.transactions, resolver, ctx); From b034860b253309ec0bef863dc5b0d550fbdd6522 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sun, 3 Sep 2023 13:46:38 -0400 Subject: [PATCH 127/151] add BLS utilities (creating key pair and proof of possession) to leap-util --- programs/leap-util/CMakeLists.txt | 2 +- programs/leap-util/actions/bls.cpp | 100 +++++++++++++++++++++++++++++ programs/leap-util/actions/bls.hpp | 27 ++++++++ programs/leap-util/main.cpp | 5 ++ 4 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 programs/leap-util/actions/bls.cpp create mode 100644 programs/leap-util/actions/bls.hpp diff --git a/programs/leap-util/CMakeLists.txt b/programs/leap-util/CMakeLists.txt index af28a0d930..0a00136ce9 100644 --- a/programs/leap-util/CMakeLists.txt +++ b/programs/leap-util/CMakeLists.txt @@ -1,4 +1,4 @@ -add_executable( ${LEAP_UTIL_EXECUTABLE_NAME} main.cpp actions/subcommand.cpp actions/generic.cpp actions/blocklog.cpp actions/snapshot.cpp actions/chain.cpp) +add_executable( ${LEAP_UTIL_EXECUTABLE_NAME} main.cpp actions/subcommand.cpp actions/generic.cpp actions/blocklog.cpp actions/bls.cpp actions/snapshot.cpp actions/chain.cpp) if( UNIX AND NOT APPLE ) set(rt_library rt ) diff --git a/programs/leap-util/actions/bls.cpp b/programs/leap-util/actions/bls.cpp new file mode 100644 index 0000000000..5afd40c404 --- /dev/null +++ b/programs/leap-util/actions/bls.cpp @@ -0,0 +1,100 @@ +#include "bls.hpp" + +#include +#include +#include +//#include + +#include + +using namespace fc::crypto::blslib; +namespace bpo = boost::program_options; +using bpo::options_description; + +void bls_actions::setup(CLI::App& app) { + // callback helper with error code handling + auto err_guard = [this](int (bls_actions::*fun)()) { + try { + int rc = (this->*fun)(); + if(rc) throw(CLI::RuntimeError(rc)); + } catch(...) { + print_exception(); + throw(CLI::RuntimeError(-1)); + } + }; + + // main command + auto* sub = app.add_subcommand("bls", "bls utility"); + sub->require_subcommand(); + + // Create subcommand + auto create = sub->add_subcommand("create", "Create various items"); + create->require_subcommand(); + + // sub-subcommand - key + auto* create_key = create->add_subcommand("key", "Create a new keypair and print the public and private keys")->callback([err_guard]() { err_guard(&bls_actions::create_key); }); + create_key->add_option("-f,--file", opt->key_file, "Name of file to write private/public key output to. (Must be set, unless \"--to-console\" is passed"); + create_key->add_flag( "--to-console", opt->print_console, "Print private/public keys to console."); + + // sub-subcommand - pop (proof of possession) + auto* create_pop = create->add_subcommand("pop", "Create proof of possession for the corresponding public key of a given private key")->callback([err_guard]() { err_guard(&bls_actions::create_pop); }); + create_pop->add_option("-f,--file", opt->key_file, "Name of file storing the private key. (one and only one of \"-f,--file\" and \"--private-key\" must be set)"); + create_pop->add_option("--private-key", opt->private_key_str, "The private key. (one and only one of \"-f,--file\" and \"--private-key\" must be set)"); +} + +int bls_actions::create_key() { + if (opt->key_file.empty() && !opt->print_console) { + std::cerr << "ERROR: Either indicate a file using \"--file\" or pass \"--to-console\"" << std::endl; + return -1; + } + + const bls_private_key private_key = bls_private_key::generate(); + const bls_public_key public_key = private_key.get_public_key(); + + const std::array msg = public_key._pkey.toCompressedBytesBE(); + const std::vector msg_vector = std::vector(msg.begin(), msg.end()); + const bls_signature pop = private_key.sign(msg_vector); + + std::string out_str = "Private key: " + private_key.to_string({}) + "\n"; + out_str += "Public key: " + public_key.to_string({}) + "\n"; + out_str += "Proof of Possession: " + pop.to_string({}) + "\n"; + + if (opt->print_console) { + std::cout << out_str; + } else { + std::cout << "saving keys to " << opt->key_file << std::endl; + std::ofstream out( opt->key_file.c_str() ); + out << out_str; + } + + return 0; +} + +int bls_actions::create_pop() { + if (opt->key_file.empty() && opt->private_key_str.empty()) { + std::cerr << "ERROR: Either indicate a file using \"-f, --file\" or pass \"--private-key\"" << std::endl; + return -1; + } else if (!opt->key_file.empty() && !opt->private_key_str.empty()) { + std::cerr << "ERROR: Only one of \"-f, --file\" and \"--private-key\" can be provided" << std::endl; + return -1; + } + + const bls_private_key private_key = bls_private_key(opt->private_key_str); + const bls_public_key public_key = private_key.get_public_key(); + std::string pop_str = generate_pop_str(private_key); + + std::cout << "Proof of Possession: " << pop_str << std::endl; + std::cout << "Public key: " << public_key.to_string({}) << std::endl; + + return 0; +} + +std::string bls_actions::generate_pop_str(const bls_private_key& private_key) { + const bls_public_key public_key = private_key.get_public_key(); + + const std::array msg = public_key._pkey.toCompressedBytesBE(); + const std::vector msg_vector = std::vector(msg.begin(), msg.end()); + const bls_signature pop = private_key.sign(msg_vector); + + return pop.to_string({}); +} diff --git a/programs/leap-util/actions/bls.hpp b/programs/leap-util/actions/bls.hpp new file mode 100644 index 0000000000..5811e84613 --- /dev/null +++ b/programs/leap-util/actions/bls.hpp @@ -0,0 +1,27 @@ +#include "subcommand.hpp" +#include + +#include + +using namespace eosio::chain; + +struct bls_options { + std::string key_file; + std::string private_key_str; + + // flags + bool print_console{false}; +}; + +class bls_actions : public sub_command { +public: + bls_actions() : sub_command() {} + void setup(CLI::App& app); + +protected: + int create_key(); + int create_pop(); + +private: + std::string generate_pop_str(const fc::crypto::blslib::bls_private_key& private_key); +}; diff --git a/programs/leap-util/main.cpp b/programs/leap-util/main.cpp index 908a760cb3..840cfa5b22 100644 --- a/programs/leap-util/main.cpp +++ b/programs/leap-util/main.cpp @@ -6,6 +6,7 @@ #include #include "actions/blocklog.hpp" +#include "actions/bls.hpp" #include "actions/chain.hpp" #include "actions/generic.hpp" #include "actions/snapshot.hpp" @@ -33,6 +34,10 @@ int main(int argc, char** argv) { auto blocklog_subcommand = std::make_shared(); blocklog_subcommand->setup(app); + // bls sc tree + auto bls_subcommand = std::make_shared(); + bls_subcommand->setup(app); + // snapshot sc tree auto snapshot_subcommand = std::make_shared(); snapshot_subcommand->setup(app); From fcded9e06298df4660a79313300c15ca37d2a98f Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sun, 3 Sep 2023 19:48:37 -0400 Subject: [PATCH 128/151] add tests for create key pair --- tests/CMakeLists.txt | 3 ++ tests/leap_util_bls_test.py | 96 +++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100755 tests/leap_util_bls_test.py diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 71147aaa34..cfae3e4226 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,6 +18,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/block_log_util_test.py ${CMAKE_CURREN configure_file(${CMAKE_CURRENT_SOURCE_DIR}/block_log_retain_blocks_test.py ${CMAKE_CURRENT_BINARY_DIR}/block_log_retain_blocks_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cluster_launcher.py ${CMAKE_CURRENT_BINARY_DIR}/cluster_launcher.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/distributed-transactions-test.py ${CMAKE_CURRENT_BINARY_DIR}/distributed-transactions-test.py COPYONLY) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/leap_util_bls_test.py ${CMAKE_CURRENT_BINARY_DIR}/leap_util_bls_test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sample-cluster-map.json ${CMAKE_CURRENT_BINARY_DIR}/sample-cluster-map.json COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/restart-scenarios-test.py ${CMAKE_CURRENT_BINARY_DIR}/restart-scenarios-test.py COPYONLY) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/terminate-scenarios-test.py ${CMAKE_CURRENT_BINARY_DIR}/terminate-scenarios-test.py COPYONLY) @@ -241,6 +242,8 @@ set_property(TEST cli_test PROPERTY LABELS nonparallelizable_tests) add_test(NAME larger_lib_test COMMAND tests/large-lib-test.py ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_property(TEST larger_lib_test PROPERTY LABELS nonparallelizable_tests) +add_test(NAME leap_util_bls_test COMMAND tests/leap_util_bls_test.py WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + add_test(NAME http_plugin_test COMMAND tests/http_plugin_test.py ${UNSHARE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) set_tests_properties(http_plugin_test PROPERTIES TIMEOUT 100) set_property(TEST http_plugin_test PROPERTY LABELS nonparallelizable_tests) diff --git a/tests/leap_util_bls_test.py b/tests/leap_util_bls_test.py new file mode 100755 index 0000000000..0ff315f2a1 --- /dev/null +++ b/tests/leap_util_bls_test.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 + +import os +import re + +from TestHarness import Utils + +############################################################### +# leap_util_bls_test +# +# Test leap-util's BLS commands. +# - Create a key pair +# - Create a POP (Proof of Possession) +# - Error handlings +# +############################################################### + +Print=Utils.Print +testSuccessful=False + +def test_create_key_to_console(): + rslts = Utils.processLeapUtilCmd("bls create key --to-console", "create key to console", silentErrors=False) + check_create_key_results(rslts) + +def test_create_key_to_file(): + # a random tmp file, to be deleted after use + tmp_file = "tmp_key_file_dlkdx1x56pjy" + Utils.processLeapUtilCmd("bls create key --file {}".format(tmp_file), "create key to file", silentErrors=False) + + with open(tmp_file, 'r') as file: + rslts = file.read() + check_create_key_results(rslts) + + os.remove(tmp_file) + +def test_create_pop_from_command_line(): + pass + +def test_create_pop_from_file(): + pass + +def test_create_key_error_handling(): + pass + +def test_create_pop_error_handling(): + pass + +def check_create_key_results(rslts): + results = get_results(rslts) + + # check each output has valid value + assert "PVT_BLS_" in results["Private key"] + assert "PUB_BLS_" in results["Public key"] + assert "SIG_BLS_" in results["Proof of Possession"] + +def get_results(rslts): + # sample output looks like + # Private key: PVT_BLS_kRhJJ2MsM+/CddO... + # Public key: PUB_BLS_lbUE8922wUfX0Iy5... + # Proof of Possession: SIG_BLS_olZfcFw... + pattern = r'(\w+[^:]*): ([^\n]+)' + matched= re.findall(pattern, rslts) + + results = {} + for k, v in matched: + results[k.strip()] = v.strip() + + return results + +# tests start +try: + # test create key to console + test_create_key_to_console() + + # test create key to file + test_create_key_to_file() + + # test create pop from private key in command line + test_create_pop_from_command_line() + + # test create pop from private key in file + test_create_pop_from_file() + + # test error handling in create key + test_create_key_error_handling() + + # test error handling in create pop + test_create_key_error_handling() + + testSuccessful=True +except Exception as e: + Print(e) + Utils.errorExit("exception during processing") + +exitCode = 0 if testSuccessful else 1 +exit(exitCode) From 3250a333308bb2efe46aef15adda5830146b6fcf Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Sun, 3 Sep 2023 20:18:14 -0400 Subject: [PATCH 129/151] handle creating pop from private key in a file --- programs/leap-util/actions/bls.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/programs/leap-util/actions/bls.cpp b/programs/leap-util/actions/bls.cpp index 5afd40c404..c99be3f6f6 100644 --- a/programs/leap-util/actions/bls.cpp +++ b/programs/leap-util/actions/bls.cpp @@ -79,7 +79,29 @@ int bls_actions::create_pop() { return -1; } - const bls_private_key private_key = bls_private_key(opt->private_key_str); + std::string private_key_str; + if (!opt->private_key_str.empty()) { + private_key_str = opt->private_key_str; + } else { + std::ifstream key_file(opt->key_file); + + if (!key_file.is_open()) { + std::cerr << "ERROR: failed to open file " << opt->key_file << std::endl; + return -1; + } + + if (std::getline(key_file, private_key_str)) { + if (!key_file.eof()) { + std::cerr << "ERROR: file " << opt->key_file << " contains more than one line" << std::endl; + return -1; + } + } else { + std::cerr << "ERROR: file " << opt->key_file << " is empty" << std::endl; + return -1; + } + } + + const bls_private_key private_key = bls_private_key(private_key_str); const bls_public_key public_key = private_key.get_public_key(); std::string pop_str = generate_pop_str(private_key); From c0ce2580106553772757c6e39b39fa0f6b0d0c75 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 5 Sep 2023 10:49:01 -0400 Subject: [PATCH 130/151] complete tests and minor refactoring --- programs/leap-util/actions/bls.cpp | 15 +++++--- tests/leap_util_bls_test.py | 61 +++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/programs/leap-util/actions/bls.cpp b/programs/leap-util/actions/bls.cpp index c99be3f6f6..01cfff138d 100644 --- a/programs/leap-util/actions/bls.cpp +++ b/programs/leap-util/actions/bls.cpp @@ -3,7 +3,6 @@ #include #include #include -//#include #include @@ -46,19 +45,22 @@ int bls_actions::create_key() { if (opt->key_file.empty() && !opt->print_console) { std::cerr << "ERROR: Either indicate a file using \"--file\" or pass \"--to-console\"" << std::endl; return -1; + } else if (!opt->key_file.empty() && opt->print_console) { + std::cerr << "ERROR: Only one of \"--file\" or pass \"--to-console\" can be provided" << std::endl; + return -1; } + // create a private key and get its corresponding public key const bls_private_key private_key = bls_private_key::generate(); const bls_public_key public_key = private_key.get_public_key(); - const std::array msg = public_key._pkey.toCompressedBytesBE(); - const std::vector msg_vector = std::vector(msg.begin(), msg.end()); - const bls_signature pop = private_key.sign(msg_vector); + // generate pop + const std::string pop_str = generate_pop_str(private_key); + // prepare output std::string out_str = "Private key: " + private_key.to_string({}) + "\n"; out_str += "Public key: " + public_key.to_string({}) + "\n"; - out_str += "Proof of Possession: " + pop.to_string({}) + "\n"; - + out_str += "Proof of Possession: " + pop_str + "\n"; if (opt->print_console) { std::cout << out_str; } else { @@ -101,6 +103,7 @@ int bls_actions::create_pop() { } } + // create private key object using input private key string const bls_private_key private_key = bls_private_key(private_key_str); const bls_public_key public_key = private_key.get_public_key(); std::string pop_str = generate_pop_str(private_key); diff --git a/tests/leap_util_bls_test.py b/tests/leap_util_bls_test.py index 0ff315f2a1..8a5fe0f7db 100755 --- a/tests/leap_util_bls_test.py +++ b/tests/leap_util_bls_test.py @@ -23,7 +23,6 @@ def test_create_key_to_console(): check_create_key_results(rslts) def test_create_key_to_file(): - # a random tmp file, to be deleted after use tmp_file = "tmp_key_file_dlkdx1x56pjy" Utils.processLeapUtilCmd("bls create key --file {}".format(tmp_file), "create key to file", silentErrors=False) @@ -34,16 +33,66 @@ def test_create_key_to_file(): os.remove(tmp_file) def test_create_pop_from_command_line(): - pass + # Create a pair of keys + rslts = Utils.processLeapUtilCmd("bls create key --to-console", "create key to console", silentErrors=False) + results = get_results(rslts) + + # save results + private_key = results["Private key"] + publick_key = results["Public key"] + pop = results["Proof of Possession"] + + # use the private key to create POP + rslts = Utils.processLeapUtilCmd("bls create pop --private-key {}".format(private_key), "create pop from command line", silentErrors=False) + results = get_results(rslts) + + # check pop and public key are the same as those generated before + assert results["Public key"] == publick_key + assert results["Proof of Possession"] == pop def test_create_pop_from_file(): - pass + # Create a pair of keys + rslts = Utils.processLeapUtilCmd("bls create key --to-console", "create key to console", silentErrors=False) + results = get_results(rslts) + + # save results + private_key = results["Private key"] + publick_key = results["Public key"] + pop = results["Proof of Possession"] + + # save private key to a file + private_key_file = "tmp_key_file_dlkdx1x56pjy" + with open(private_key_file, 'w') as file: + file.write(private_key) + + # use the private key file to create POP + rslts = Utils.processLeapUtilCmd("bls create pop --file {}".format(private_key_file), "create pop from command line", silentErrors=False) + os.remove(private_key_file) + results = get_results(rslts) + + # check pop and public key are the same as those generated before + assert results["Public key"] == publick_key + assert results["Proof of Possession"] == pop def test_create_key_error_handling(): - pass + # should fail with missing arguments (processLeapUtilCmd returning None) + assert Utils.processLeapUtilCmd("bls create key", "missing arguments") == None + + # should fail when both arguments are present + assert Utils.processLeapUtilCmd("bls create key --file out_file --to-console", "conflicting arguments") == None def test_create_pop_error_handling(): - pass + # should fail with missing arguments (processLeapUtilCmd returning None) + assert Utils.processLeapUtilCmd("bls create pop", "missing arguments") == None + + # should fail when both arguments are present + assert Utils.processLeapUtilCmd("bls create pop --file private_key_file --private-key", "conflicting arguments") == None + + # should fail when private key file does not exist + temp_file = "aRandomFileT6bej2pjsaz" + if os.path.exists(temp_file): + os.remove(temp_file) + assert Utils.processLeapUtilCmd("bls create pop --file {}".format(temp_file), "private file not existing") == None def check_create_key_results(rslts): results = get_results(rslts) @@ -85,7 +134,7 @@ def get_results(rslts): test_create_key_error_handling() # test error handling in create pop - test_create_key_error_handling() + test_create_pop_error_handling() testSuccessful=True except Exception as e: From cffb76e580d7a18533c33e915e5597cc0828cbf5 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 5 Sep 2023 11:35:34 -0500 Subject: [PATCH 131/151] GH-1523 Finish set_finalizers and add unittest --- .../eos-vm-oc/intrinsic_mapping.hpp | 3 +- .../eosio/chain/webassembly/interface.hpp | 11 ++++ .../chain/webassembly/runtimes/eos-vm.cpp | 1 + unittests/protocol_feature_tests.cpp | 64 +++++++++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp index ea92a9cf86..6d8b9b5141 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp @@ -277,7 +277,8 @@ inline constexpr auto get_intrinsic_table() { "env.bls_pairing", "env.bls_g1_map", "env.bls_g2_map", - "env.bls_fp_mod" + "env.bls_fp_mod", + "env.set_finalizers" ); } inline constexpr std::size_t find_intrinsic_index(std::string_view hf) { diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index 24dc555250..bf40b47a7e 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -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 public_key_g1_jacobian; + * }; + * struct abi_finalizer_set { + * uint64_t fthreshold = 0; + * std::vector finalizers; + * }; + * * @ingroup privileged * * @param packed_finalizer_set - a serialized finalizer_set object. diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index e23f91b90e..d0eaea4b32 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -357,6 +357,7 @@ REGISTER_LEGACY_HOST_FUNCTION(get_blockchain_parameters_packed, privileged_check REGISTER_LEGACY_HOST_FUNCTION(set_blockchain_parameters_packed, privileged_check); REGISTER_HOST_FUNCTION(is_privileged, privileged_check); REGISTER_HOST_FUNCTION(set_privileged, privileged_check); +REGISTER_HOST_FUNCTION(set_finalizers, privileged_check); // softfloat api REGISTER_INJECTED_HOST_FUNCTION(_eosio_f32_add); diff --git a/unittests/protocol_feature_tests.cpp b/unittests/protocol_feature_tests.cpp index e167e13d6b..b1cf3f1656 100644 --- a/unittests/protocol_feature_tests.cpp +++ b/unittests/protocol_feature_tests.cpp @@ -1929,4 +1929,68 @@ BOOST_AUTO_TEST_CASE( set_parameters_packed_test ) { try { c.error("alice does not have permission to call this API")); } FC_LOG_AND_RETHROW() } +static const char import_set_finalizers_wast[] = R"=====( +(module + (import "env" "set_finalizers" (func $set_finalizers (param i32 i32))) + (memory $0 1) + (export "apply" (func $apply)) + (func $apply (param $0 i64) (param $1 i64) (param $2 i64) + (call $set_finalizers + (i32.const 0) + (i32.const 4) + ) + ) + (data (i32.const 0) "\00\00\00\00") +) +)====="; + +BOOST_AUTO_TEST_CASE( set_finalizers_test ) { try { + tester c( setup_policy::preactivate_feature_and_new_bios ); + + const auto alice_account = account_name("alice"); + c.create_accounts( {alice_account} ); + c.produce_block(); + + const auto& pfm = c.control->get_protocol_feature_manager(); + const auto& d = pfm.get_builtin_digest(builtin_protocol_feature_t::instant_finality); + BOOST_REQUIRE(d); + + BOOST_CHECK_EXCEPTION( c.set_code( config::system_account_name, import_set_finalizers_wast ), + wasm_exception, + fc_exception_message_is( "env.set_finalizers unresolveable" ) ); + + c.preactivate_protocol_features( {*d} ); + c.produce_block(); + + // ensure it now resolves + c.set_code( config::system_account_name, import_set_finalizers_wast ); + + // ensure it can be called + auto action_priv = action( {//vector of permission_level + { config::system_account_name, + permission_name("active") } + }, + config::system_account_name, + action_name(), + {} ); + // if able to call then will get error on unpacking field `fthreshold`, top message of: 'read datastream of length 4 over by -3' + base_tester::action_result r = c.push_action(std::move(action_priv), config::system_account_name.to_uint64_t()); + BOOST_CHECK(r.find("read datastream of length 4 over by -3") != std::string::npos); + + c.produce_block(); + + + c.set_code( alice_account, import_set_finalizers_wast ); + auto action_non_priv = action( {//vector of permission_level + { alice_account, + permission_name("active") } + }, + alice_account, + action_name(), + {} ); + //ensure privileged host function cannot be called by regular account + BOOST_REQUIRE_EQUAL(c.push_action(std::move(action_non_priv), alice_account.to_uint64_t()), + c.error("alice does not have permission to call this API")); +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_SUITE_END() From 814df9773996da63bf03aeebc1429a39e74ee736 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Tue, 5 Sep 2023 17:07:19 -0400 Subject: [PATCH 132/151] incorporate review comments --- programs/leap-util/actions/bls.cpp | 8 ++++---- programs/leap-util/actions/bls.hpp | 1 - tests/leap_util_bls_test.py | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/programs/leap-util/actions/bls.cpp b/programs/leap-util/actions/bls.cpp index 01cfff138d..ac7a1fa645 100644 --- a/programs/leap-util/actions/bls.cpp +++ b/programs/leap-util/actions/bls.cpp @@ -23,20 +23,20 @@ void bls_actions::setup(CLI::App& app) { }; // main command - auto* sub = app.add_subcommand("bls", "bls utility"); + auto* sub = app.add_subcommand("bls", "BLS utility"); sub->require_subcommand(); // Create subcommand - auto create = sub->add_subcommand("create", "Create various items"); + auto create = sub->add_subcommand("create", "Create BLS items"); create->require_subcommand(); // sub-subcommand - key - auto* create_key = create->add_subcommand("key", "Create a new keypair and print the public and private keys")->callback([err_guard]() { err_guard(&bls_actions::create_key); }); + auto* create_key = create->add_subcommand("key", "Create a new BLS keypair and print the public and private keys")->callback([err_guard]() { err_guard(&bls_actions::create_key); }); create_key->add_option("-f,--file", opt->key_file, "Name of file to write private/public key output to. (Must be set, unless \"--to-console\" is passed"); create_key->add_flag( "--to-console", opt->print_console, "Print private/public keys to console."); // sub-subcommand - pop (proof of possession) - auto* create_pop = create->add_subcommand("pop", "Create proof of possession for the corresponding public key of a given private key")->callback([err_guard]() { err_guard(&bls_actions::create_pop); }); + auto* create_pop = create->add_subcommand("pop", "Create proof of possession of the corresponding private key for a given public key")->callback([err_guard]() { err_guard(&bls_actions::create_pop); }); create_pop->add_option("-f,--file", opt->key_file, "Name of file storing the private key. (one and only one of \"-f,--file\" and \"--private-key\" must be set)"); create_pop->add_option("--private-key", opt->private_key_str, "The private key. (one and only one of \"-f,--file\" and \"--private-key\" must be set)"); } diff --git a/programs/leap-util/actions/bls.hpp b/programs/leap-util/actions/bls.hpp index 5811e84613..aba3545e5e 100644 --- a/programs/leap-util/actions/bls.hpp +++ b/programs/leap-util/actions/bls.hpp @@ -15,7 +15,6 @@ struct bls_options { class bls_actions : public sub_command { public: - bls_actions() : sub_command() {} void setup(CLI::App& app); protected: diff --git a/tests/leap_util_bls_test.py b/tests/leap_util_bls_test.py index 8a5fe0f7db..e4a2e28f99 100755 --- a/tests/leap_util_bls_test.py +++ b/tests/leap_util_bls_test.py @@ -39,7 +39,7 @@ def test_create_pop_from_command_line(): # save results private_key = results["Private key"] - publick_key = results["Public key"] + public_key = results["Public key"] pop = results["Proof of Possession"] # use the private key to create POP @@ -47,7 +47,7 @@ def test_create_pop_from_command_line(): results = get_results(rslts) # check pop and public key are the same as those generated before - assert results["Public key"] == publick_key + assert results["Public key"] == public_key assert results["Proof of Possession"] == pop def test_create_pop_from_file(): @@ -57,7 +57,7 @@ def test_create_pop_from_file(): # save results private_key = results["Private key"] - publick_key = results["Public key"] + public_key = results["Public key"] pop = results["Proof of Possession"] # save private key to a file @@ -71,7 +71,7 @@ def test_create_pop_from_file(): results = get_results(rslts) # check pop and public key are the same as those generated before - assert results["Public key"] == publick_key + assert results["Public key"] == public_key assert results["Proof of Possession"] == pop def test_create_key_error_handling(): From ab4c1eb68e0b1320795b224d3dee439b4102944f Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 5 Sep 2023 17:41:08 -0500 Subject: [PATCH 133/151] GH-1523 CDT will use Affine little-endian format. --- .../chain/include/eosio/chain/webassembly/interface.hpp | 2 +- libraries/chain/webassembly/privileged.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/chain/include/eosio/chain/webassembly/interface.hpp b/libraries/chain/include/eosio/chain/webassembly/interface.hpp index bf40b47a7e..f93225c5e2 100644 --- a/libraries/chain/include/eosio/chain/webassembly/interface.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/interface.hpp @@ -180,7 +180,7 @@ 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 public_key_g1_jacobian; + * std::array public_key_g1_affine_le; * }; * struct abi_finalizer_set { * uint64_t fthreshold = 0; diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index 5aa052e4e8..a447154390 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -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 public_key_g1_jacobian; + std::array public_key_g1_affine_le; }; struct abi_finalizer_set { uint64_t fthreshold = 0; @@ -183,7 +183,7 @@ 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 pk = bls12_381::g1::fromJacobianBytesLE(f.public_key_g1_jacobian); + std::optional pk = bls12_381::g1::fromAffineBytesLE(f.public_key_g1_affine_le); 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, @@ -272,5 +272,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)); \ No newline at end of file From fb939689f031730f8635368aa462f223aca8e40e Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 5 Sep 2023 18:00:13 -0500 Subject: [PATCH 134/151] GH-1523 Remove unused spaceship operator not liked by libtester --- libraries/chain/finalizer_set.cpp | 2 -- libraries/chain/include/eosio/chain/finalizer_set.hpp | 2 -- 2 files changed, 4 deletions(-) diff --git a/libraries/chain/finalizer_set.cpp b/libraries/chain/finalizer_set.cpp index 6fa56a2b0a..0e91c64930 100644 --- a/libraries/chain/finalizer_set.cpp +++ b/libraries/chain/finalizer_set.cpp @@ -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 diff --git a/libraries/chain/include/eosio/chain/finalizer_set.hpp b/libraries/chain/include/eosio/chain/finalizer_set.hpp index ced75ca27c..1966eadd25 100644 --- a/libraries/chain/include/eosio/chain/finalizer_set.hpp +++ b/libraries/chain/include/eosio/chain/finalizer_set.hpp @@ -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 finalizers; ///< Instant Finality voter set From 26b87e7063545adff5e641ae1ed9fdcffef1237c Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 5 Sep 2023 18:09:16 -0500 Subject: [PATCH 135/151] GH-1523 Update deep-mind test for new block extension --- unittests/deep-mind/deep-mind.log | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/unittests/deep-mind/deep-mind.log b/unittests/deep-mind/deep-mind.log index 7c84eacf23..864645238c 100644 --- a/unittests/deep-mind/deep-mind.log +++ b/unittests/deep-mind/deep-mind.log @@ -29,7 +29,7 @@ DMLOG TRX_OP CREATE onblock ef240e45433c433de4061120632aa06e32ec3e77048abf55c62e DMLOG APPLIED_TRANSACTION 2 ef240e45433c433de4061120632aa06e32ec3e77048abf55c62e0612c22548ed02000000013b3d4b010000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e801006400000000000000000000000000000000000000000001010000010000000000ea305506d4766d9dbedb630ad9546f583a9809539cf09d38fd1554b4216503113ff4e501000000000000000100000000000000010000000000ea3055010000000000000000000000000000ea30550000000000ea305500000000221acfa4010000000000ea305500000000a8ed323274003b3d4b000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044423079ed372a4dda0bf89c3a594df409eaa8c1535451b7d5ca6a3d7a37691200000000000000000000000000000000ef240e45433c433de4061120632aa06e32ec3e77048abf55c62e0612c22548ed02000000013b3d4b010000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e80000000000000000 DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":0,"value_ex":0,"consumed":0},"average_block_cpu_usage":{"last_ordinal":0,"value_ex":0,"consumed":0},"pending_net_usage":0,"pending_cpu_usage":100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1048576,"virtual_cpu_limit":200000} DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":2,"value_ex":0,"consumed":0},"average_block_cpu_usage":{"last_ordinal":2,"value_ex":833334,"consumed":100},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1049625,"virtual_cpu_limit":200200} -DMLOG ACCEPTED_BLOCK 2 02000000020000000000000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010001000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba10100000000000000010000000000ea305502000000010000000000ea305500000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e8013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0020701fd1d2d6fbca71ad1df5bd09a987d6863f301b93acfc1c34857e4b2f53821a0b4ca8483cf594f845f3f4fc155dbbc98009cb9c7b7b60d449f922dc00abcb0f0000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0001013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0020701fd1d2d6fbca71ad1df5bd09a987d6863f301b93acfc1c34857e4b2f53821a0b4ca8483cf594f845f3f4fc155dbbc98009cb9c7b7b60d449f922dc00abcb0f000001 +DMLOG ACCEPTED_BLOCK 2 02000000020000000000000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000001000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba10100000000000000010000000000ea305502000000010000000000ea305500000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e8013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0020701fd1d2d6fbca71ad1df5bd09a987d6863f301b93acfc1c34857e4b2f53821a0b4ca8483cf594f845f3f4fc155dbbc98009cb9c7b7b60d449f922dc00abcb0f0000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0001013b3d4b0000000000ea30550000000000015ab65a885a31e441ac485ebd2aeba87bf7ee6e7bcc40bf3a24506ba1000000000000000000000000000000000000000000000000000000000000000062267e8b11d7d8f28e1f991a4de2b08cf92500861af2795765bdc9263cd6f4cd000000000001000021010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0020701fd1d2d6fbca71ad1df5bd09a987d6863f301b93acfc1c34857e4b2f53821a0b4ca8483cf594f845f3f4fc155dbbc98009cb9c7b7b60d449f922dc00abcb0f000001 DMLOG START_BLOCK 3 DMLOG CREATION_OP ROOT 0 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304002,"value_ex":0,"consumed":0},"cpu_usage":{"last_ordinal":1262304002,"value_ex":1157,"consumed":101},"ram_usage":2724} @@ -129,7 +129,7 @@ DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1 DMLOG APPLIED_TRANSACTION 3 dd3c62c2bccdf1a4ca01464e03c6deba265089df27e9ca08b3ec671f424a4e7e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190100d007000010000000000000000080000000000000000001010000010000000000ea3055ac6be432e6c9fa887fb2ef020e979c440cb9a3f3458375d7dafa7e510aded96f18000000000000001800000000000000010000000000ea3055180000000000000001010000000000ea30550000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc00000000000000000000dd3c62c2bccdf1a4ca01464e03c6deba265089df27e9ca08b3ec671f424a4e7e03000000023b3d4b0100000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7190000000000000000 DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":2,"value_ex":0,"consumed":0},"average_block_cpu_usage":{"last_ordinal":2,"value_ex":833334,"consumed":100},"pending_net_usage":9696,"pending_cpu_usage":44100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1049625,"virtual_cpu_limit":200200} DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":80800000,"consumed":9696},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":368326389,"consumed":44101},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} -DMLOG ACCEPTED_BLOCK 3 03000000030000000200000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100012d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b0200000000000000010000000000ea305503000000010000000000ea305502000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df719023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000001f20041c84dfa3dc10503182e60706eeae02db7fbda81f47ea43d623f3dfd84c7b5e063a2ee30ba7f62984f4e87938e34e291f4425f7180ae676c8a02083f489970000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0001023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000001f20041c84dfa3dc10503182e60706eeae02db7fbda81f47ea43d623f3dfd84c7b5e063a2ee30ba7f62984f4e87938e34e291f4425f7180ae676c8a02083f489971600d0070000fb05010100203b7de491b51d3d74624078bc2c5dc4420985f0350afb6923a5585b5621750c9f126d7cff0efeade2068c7b618fc754b2abb5bff8cdb9bd0ecb4432b72ae1ed380100a82f78daed5c7b8c5ce755ff1ef7357b67e3ebc6d94c3609f9e662d0b8a4659bb8eb2575dbbddbc476694b9cca2dfea3b0bbd99d647776bdbb9e1da70e0adead081045158a7894b6405524a4d21424545aa8cacb0d0815a94891fa20414284ff2a025511a245ad54737ee77cf7ceeccb71f09a87545b9e7be77b9cef7ce79cef3cbf71f44fe94f1bf5d03d9f1951f447e343fdf3d87be873f2879efef473830dea77fff59e7bbef7f440d3bfd197d9f57368d1bfa54767949ab11b9736d48cd9b8840f7a0b372ed11f35136cf0436fe80dfac0b80dbc2afa67f84d6306e6063201ad97a8ff9234d00880f033d54c84469e48cd68b03c8b3ea54dd0909531c1fc52d0b0ed95c70e2dae4f3fd29eed5de8b6a767e77a8b8fcdf6daf32a42d7cd6bdd76d9548e51317aeaedd5f5c5d5e9d9f5f576b7a72c9aa273ed73ebed9e4af025c3b4d595e9f9d9deecf4fae2cfb4558d9b09defcf4409f1a2aa7cead3d2e53ebddf6f90b8b40e6426f41a568ba89e04eaf75171f5b5c6e3f4ac8d519393476dbebab17ba73ede9e5c5738bbd75358c9e70f6e155c24ae17d44a6aeaeadaeb7e7f1327f61aedd5d5737a1d3a1f3e1e5d5b9a5b985d9c595e9b5d9eeecb9768ffae9756e8956e29db9475f6918efa23e77a1db6daff4a67b8be7daea00d316339982ed81b579743afff0f4238b2bf3d38be347558696da34d17361b9b778af3a88ef0707693c3db73adf56868958aed36dcfb5097257d61a2280580ef09890d1fac2ec3d6f1c57af61e4a877bdb74a6445ffcd681aa6a60b6bf3e02dda0ed993275414abb8369444511c0f0d594b9f517c8b1e31237624a07ff4371cd123d60e51efd0adb7da86ff63ab8f46725b10ea353d34145aad7434623774b17959a51baaf8d45f568fb8a6c3d9b5b5e5c7d5eb6a07b42a745a7bfdd83d47c727ee7bd39b87fe66539f0854767bbaa9b5dd3093f2d7a9078655417f5be683f4a5c81ecb752737e3f44d5a9f9cccad539d22ee1417cfe76a9c1a9c29b29e53ef1ad64e4faa62e3c4b0a9dbb45007e81ff5e90e663b4d2fe83d39aca9bdf8cdcb2a33ce1e489d4d8d4ac7b5def8415a6e29a755c64d9d66d262f59651832ba175dc6cd2f3ad0a40313352c533b4f3ffd03ada2854d3601718b7043ccf3b757258611fef0076d96d07d2ecce62649cc0127ae5968b8d4e1e38ddc96ecbb17da75c405b74f67c6e4ed034553cd1c92da19207457c3ed70f0c1b0c21ac685a71b19387d4d78c9c75da192c1c776901daf9131d02648088f62d173b2e62184ec68434c5f29bca465367881c84970c54f4d1c22c80549d0a2430a126fe9ede4b742b469a9637a28be0ed843e6191fd00d024d49de6bd366d0a5a6777d2dc74429b0dde36f5df9e6bec7a5859225a9339fce1c9dc60ae39a894d39e26292146a426345d7a93f272c2484b6b9e2e1154e1a0398c01a6a8778011febd839629d7b3d95d34d54c62415e4c31a2584ca6381a31acea26051d200bf4245168a23feb1ca6d5d2043cd2d9e1eda8f8f61f4e43950da9f42744a85e22fae9c3a08b2e5e0021137ecde82da8ded0adb2d78ef257a75be822622d65756a7949d1bae92fd774c0846b1104fa0872b354c43fcee7e5eb2cceaa08c0b2a62194695a9245a3dc961b6c411509c9112f456fcd80799088f838bb54d8415018cf5c23410b00c783082a10f50e84dded3abb44840118013088481f4a76fd881cda17441ad78fc81dfb8288bb7e440eef0b22adeb47e4ee7d4164ecfa1139ba2f884c5c3f22c7f70591cb6a174cf45e9898014c4c05e33982a10750d17ba2a2050223a0592d1118361ae9778cd51be612eb3957aa3975c4aadc4cb9a78eab14d660aa456f43fc36466f357e9ba03728426c01e32d8f870db33cdef01bc66b7ec378b62d9fc883fbd4017a0b8ae4b1fbd44dfc96d1db30bf35e8ad8e193c2eaec645d5b8b01a17f0fa0d5edf1c57b70aee99c7e5f60a97d10a97db2a5c1abc0b8cbbb9dae36baa3d1eacf69809ce8a9118e10581c42db234bd1d1264d57dea2e2107b5fd4035eece6adc1d6459c844b286602bf4adefd3fe7f92f6da533efd522076fd194daed5619535e0fa38f56e78155bff121a57aefcf1b77ee7d73ffde2d44f929380af57ae7cf6db5fc35720b9b9b9f9fca7fff04f3e72cf43c356be5efe95ef50ef43c3817cddfc230c7ef770e22c7c910f12ba05b9544fd1d3d923f6297dccb263414ecb8f8ed693d42f71e55b1f7e71ea3dbcc4339f7cf1c57ff8e047bef6f98d3ed0bfffbddfa0efef1e8e05ea3c3dc8c59e119833c76c4b409205c8de305a8f539ef639d94705e5437ffbf257805a244096e9419a6541802c1cb3ce03719decded17a94fab537bffde13e10c0fc28808402e4494c08c8c5f6fbdba4fd251e4ed2c9de385a0f531979861ee1b8392de34e1fb3137ed844273b365a0ffcb01e3da271b326c3d68ed9861fd6e8643f365ab77ed83be9118f9b5332ecd4313be98791a20538e3c73d013cc6cd451977f198cdfcb8ac931d1fad6b3fec7df4a88d9bb332ecec313be6878d75b2b78c52f891dd415f9ed190a6d7283eb3194e0bf99b27b324fdb2d131046c8ce4ab19389231e8eea0198a568f24ccc8823c7e4064cec5c507d8f58eb3db9a86d1a0a6039d62ed3cbbc37007e32c240f3f2848d65b2e98526010b5769ab010ae038f30f1b0e277b025f8f92fc012a09310635fd260540df077b6d2bce4647f5eea12572b34fae9bc53d4007b414c1f3719351cc2e45a47da98c714f14094031716fa8220d5eabc4ea926751db1ae09479bbacec3d7e6082462fb1461abca25c5157dde4507b51a2086c978c36344650a3d2378e671fa73468757a36d79743d753d30ed296b52d09ec5612f0283b22d4fd91dd44c795b25e102f218997a4c0750d45614c9842289d0ac0145dae9d3e6886dbd0245a283666f5a0cf7652e3b927edb50e84a24f9b8b911f2f6450ad6157d667654f6725c1e13781095c6095c40a756866653a3bc550e555cd032934211daf1045303a7069d09efb9ea4c8ed96760595ee05e97205a1662d29e4bb22a1c7fa6ae9359cfe89cb9c55d2f6881ee71268c99452f700b562d5b1a1523aec20199181db4bb70e1e346d870f3e0d1c79cac96feaa3511197562c7a6be91227a4a1e93f2382d8fb3c29aa3f218ab38045e819050a478bb8c2816e738036dbe496c7b2b734d58365171658c8f34c2d75d5846ebcdc8eced1c6b0d722c138e3564d24cae847bf4581304060ec559728fe871baa9f138454a891e93cda1abf069c8c125c2790976e1d4a6de7960ee4ebf6775c207e6867108142639236748b4227fcf8884fefb560ebe02cf66fa3cdbd4b229614a764ab856bb1ad78840bb706d53ced910b85613ae65c0d8d5ae81718cc54bb2c31a2ca4eaaf98418892b289d978cc2ec8db647f6dac54cd430309821d9c450e083949b2b45f31bbb673bbb9f7b9f5d2f05e4e35e586844ea48239adfc6095dd46019b2246227596a5a3900f24d5c897ec33dbed18927e2e14b3ff4db5b71e8e2b5d9c94ba38f1eb267d5d9c6c93aaa4b4fd7071f6949a44a4060a93c5252b46af76aa9f17f9a8ed38d5a72be161d1b986537d7a40386604cfb395626a99fbd91010518ab173cd9a77ad2db8572bbef6ec575ffbe030ab7ea44c3397c7d43ab6ec7d8b182e223fcef421e535c0d2a77032e9f85b56ebe8815339b682d93966a4d726348cef82e03b431009d0e9a53c06b221840833428f28fca9af13a231231a6e4174461ef38209a000d1b08f682888f2bc15993a2f324be42e6596e6cd88d6f1d0e22c4fa5fdf440fb99b23d19907119c6f957efacdd4fed792a6a1ab27f2015ce672d957a25426f3763619dfd083b3a2f3e074727ad952a33fd4598347de34ddae92d7af1ecdede06fb1ba52dfb22f46243ccbad8b2c957f040763767c99ee6ec2a0ec8cc80ffb1b6c5b5d8d59c5d456f95562cbc8a15bb8c8481bec479f2cb8a83576477103b2134297833766a03e859f16345c3e5014e2ce144f8fbe347e87338f7d17ff9cc37de40bccf5038390595c4d11069b50772d522cd826f2758303e7b993d600b7e247ed49492c8ee0436d4cac3615d2f87d4113d31a3127ecb3a651878d20f7e6058a7a20b8abb3b790492d3493b816202e9da850e1020c1715cd2e19ac0034c1412e8900b3329c7b818a4a038c326b5442e947a482ee11feb6eff967ecc4af4b0a93df57212ab2306e25629e6b054cca1e742d857cce136e90dbd62862e15511a70ca4eeda2a343d6d1c66ba3ad815acb1c45be8e75370825dac2727c717440afb364676ff3ca3de21e7a1b14e6ad2e40eca2bd1db718648f2a151f5d9be326fa1af179c04a964f23407ad373ff00fdbc66e20a9868a6e24b34d070054ab45329e15f30da6e38613b54129f42944b2cca25c1d2568a599fe40cc08a40086639cbca8bf9c04cb15c21c6dd3f90287bec23b44687a34186a6010df5a3dc6e83a6fb395d55ca871ec8e932b4f4dff50d2261b00709d51e2095b84c7b8084d0ecdfa6bf6e593346bcf1a069a6147c3bae9271dabb19d2f18e2ca7f470d0d4db7989efc2d471029d4b6e48579071e69a73cee2097b75459d7711f21379d4fbfd27096e54c49d664487980c1249ee79d2435ea9f20e12d9526d891c083a7af613b97950aaaa2e5ecadeeb7bcb8de5c949d699d0facebc0b03a983cc81613726c1eee85b728274a564f0835229d2eeb4f5cbd2495adaa14e7857b52a5bc14dd007466aba21a8e469a2b7d124d84a934068120dd224649a18a189014d42170dd0049ed95b0cb248f5bedcb868a9703bd0447291c8da1c40b3e93940be207c54a4a6b886bc7b117510e2401155977b7f1545d441506511065af8da8aa8bb2162b13bfbaa8ba8af0e9143fb8248e3fa11b9635f1071d78fc8e17d41a475fd88dcbd2f888c5d3f2247f7059189eb47e4f8be20b27b11752f4caeb188ba072aba84b05b11f5b7c52f0ff7d1fa243badcfa0a68d5cb2cdfa88ed89c5ba180a3b617822313ce4122f650f55db492aa32ac3c5b925e55d591f52c61c4103346f04d4499660a128307e701712259ca6a0686e2bb738620389fe53f74397cc27502417c677740825f24bab6b48755e104ec1521e88c7b8f1ce61d6e6e46052e81dba402e3489b3cf8fa03f5130266727d7127d87f065450042870b65e4efa896783641cea40b386e534211cd496d89d4789ce65d6a7642602ea55261d877e1a00417a5b0469efa6b46c81821b6fe0b6b62899edd12a79ce47a13416de4108f3b1855443db8d34456556e6d69dc1c433585c2a0f0a4bfcf147074c48d4027e4ea1c9132aceea269dcb2cb0ee54c30d0ed0301b22bf0edfa910ba49183f2e21b12d20588700a0d3bcc63b343a374ba98ce0a914bc8ac629a6cad8684a5810d61c3622925253cf062a7b86bcbd8d82585e3b1a0d551445308dce98108b526112af5d4ab6b75779010321fe9dd61c70f725aa32665158d143697eb10a2b01cc41c82e32d92405471e94a3e90612401c97eca45083c25b8268fb4d1d41e0ce8076632174bd2a67fa5ad2106a2649c079c11d2888b9504c57fc69b03ba4896dcfc1037be2c3b66998e24f0e18f983d667203d9e6e771760b4d8c789c4cfcd873c20fe2dfe94e19df97c5a6b314ac09050981a3ac1d5bd9ad0c0195f7337251b13375c94553fa09faf8d9f7de4e6c232e51b0fa5d4d7e93d4cd82c39c1c3a46b84cf2da25da4ffb1217d21d874a0a071c1712754422ac5c05e864ef1b958188092d5f02909091a01ecd43cf46f60724b28fd9aa7b26c6583e41264cea100a706249b344b44b6622b49296b48eeb94c50a30904f218e9b5c4f844a75c8b130982d4c948a59fa211b0a0b858d14ae8b0ae228c9ee0c4228a4b96bb72004210dc270e5d930600b1c3026c54f683635ab00d6fa688af860cb443a244c1583c0389a4a7e01d9bc3728f5641e4c4d3cf524498b2e363ad80cf5b1f9206340d0ab2081149a08de95e7fc098c40c9b084430c670cf840c2c30f80c1001c72a3194cc61aa744850e3d04b1b03d3ab8d9413ec822bd068f000b0550d7b21ea77848e6d0820405be34e44ba3c3bb979b21d294f9a6ac6c324898105f3eef85321bd08c03a944affa37399518f854a264b612a46b78e9665837e93605c7df919d97b17e9c682fbe3dbc5d7dd9d216f910179773b795c36d3596d57b7a3f85d95244a87095c41ae3ab3cbe7a2fd4522e197c1fc80d02f26553a9bb6d92b5975c9529ea3da1226175581e8e9d003afca4be5a223c8d1dd6b1ca4d86d089879b7c07a5515d1e6079e220f730fc4f674e6e99ea7c4a6fcbec5b315b97b3f59eb3ab0923db26f00ea026b3fed1701dc9cabe6d5492748924e97c0ed7882d6435fae7b86830703b4af160f1a12cd9b407799af2ae171cad3c821f620a5c698a59f511d988b0c5f7a8016e3f291dc2ab0777d1456fbf1dd503b80a996be23700e23d231d6c71ef05b7b3011d3bf7fefb062960728e82342d8b6b900cc5e50dbec311c38292e1586a4afa350f91f328e15902d5b4151ce636bcf6509cd8a85526bf902f5e62d5e00b4f7cc58ebdddca313462bd02c9e921b5ca387a6374204d9fd7261057f07f5de10d68ba6d6a8ec28b4a668ed804fecbeb540c5394c5d81d5f712a95e0a70ced28d8eedc5edb8e1a7e478d6bd851c38f7ba51d855e77e73bb7c585403f322b4766db062503831a25811a7bd801efdd8148311e194556f468346b4cab1ae221176535ef4aa65ff6d6eed590ea1a69b4cfc4317b11a74ca76571b9a9bfb6b2295454fcae08e7607b2565b3aaa404a2baab4a4a807d04be9262717acec8035703032e989c159d754a640147f079ae90f81a37d0872a65dff3ac04ce72a710f181af81841c78579d196a20b6ac8184acb2b8936f32c9302e78707dade56f56a20632263d6b825352ba0e16c569cb65eec0578e41c4c1dab154bf387e0dfaa5635b2e17c0a3adc0700c2faa861597e8700e1ffad5e320f5fa3b9b280b2c81e86e0616488598c1f5dbefe7769ac8451714c7a02d898f57d1edb4a36dea1dc96dafe17d65bcf82a3dd99b868e47bf293ef9d5676f19d0f2b401d6f296b53c59956552f441a5e80df39698a53c4dfd83ec68f9e6aab746f596f937291396399eb1dd6d848574f66d44c0587438c5cd2ca9ec036cf37f0b0de3ebb0c8d80d9a1672b079a95dac8b45a2e2f439ee36e2e48b8db192b550550564771bc377292cdb98a735bb4ffca3a5fdf47ccec8e3b4f77ce450ca314cf8d69fe8047a3f22878e20fcdaff19f79e7434a3c746ebefac0dca7bf7dfbc36328542a6edb820b046600432719855c908c5604614532916a51dc32363fdba353d22d40c25b264e141fc88e82de6f851fa0349af1889da620490914b38808c3880440e860248c3c16513f65ae35786fd00d2ec08206309203d9c12f92a808ca6b80254c19100d29401a447c5226ea72f6500697d00197b3be92355e5d713a3238999b16dc1a2646ac606e245d6be134c3ebc8d41b32bcfd0ec6ed1e3c48a97becfd8ffff8cf51750b65c46aa38fcb211ed36e06ddc30edc657387689ea5ae68c04575f54db8239f95583c21d259e3d51a9c80984574c3ab62bd2debfb351fa2b49df5f09d88a559dc9167f25e0247f69659ca9fc9586f82b6ec05f69f5fd9506dfb13c25f8bc593c83898168ef7819edb16790fea93656c29531b92dc3e9b631e7adb35c01e3727499d6e15008d849b3385d64ef9638319907d92dcef6af04245d64f6d8be210d990cdc472248b8432a9797f8f46523e3e668992de55ca7de35d729a1aa53e9b3b8ea53ba3241e5b634cec1ad82dbf229f257908c2c9ec50b0e635956966141f1157268c47b09e0bdc470e7254625ff212e1ae2bd9832f41c702bb4fca25bfb4b4174e61acb79826461243f15364c32fc34462ea121730a88b0635c868d7c0e5c2e0918c13f3ec1ee2049d102d7fe49ea16fc85002be94fc0ae8acafc3b702f455adcf7b5f2e46906e10294915cc077a9785d5d9574627f8904bb8a21f13edb8a7ed9063b20a15ccd22152117b762a0148b24c4e5c5ad7e469696ab344d799b2b4dffd1a6fc93fef49d8fcc2e2eb7e75d6fd5cd2e2fafcecdf6da6e6df6d1f6ba5a7db8d39eebd197f575e95fecb5bbb3bdd5ee34ded7ddca6acf2daeb87317967b8bd38b2bf3ed8b8a7f0c99def9fe2e0d55ed6e77b5ebf07f5b2cae3c5a4d567cacd310ed8a33e0e9bd73b32b0036476db4baacbb0ed8bdd98797a9e111374bfd0bedae9b5b5de97567e77a8aeb00e9eb77e0786e757ef191c7f744efe581e5fcd06b5cee63cfa9f44df21f4350bb47786176e551225777f1dc6cf771b7d47edcbd7fa1bde22163d7b32b1ebe62cd9ae66bddd5deeadceab2f3ff71488969ffff18e132651a3cdac61cb22ce9dd1756da17d70806ed50684aa83eb278b13d3ffdf0e3bdf63ab05cef752fcc097569ee1f349552ff05ee7357f400d00700008101010100204b21f3cba072cc493e70861540df4677b498b0505a8b8e2a346b85a0c2dd2fc4263c4a7d8629026c4eb594ad96fac2bfe5f8ffebb9c841c353920b7b8ec11abc0100d90778da8d563b8f1c4510eedbf7e37cf209d9e60808402496c0dcdaac4e8ece01090112afe83043ef74ed4e6b677a86ee9edd5b3b2121b049888d842c84c0c1456702eb20b036424242c2e00408800c24fe03d53db3f33a58e860b6bbeaebeaeaaaafaab7f55bff9d1a796df0e5798263c37cc89f2fbe657e1eb8c7cb92e0de5f83c1eded95e4fded2d08150faf5ea5237e69f7855db2d3c199e351e5915a339c0b900d4103681849dff5c09daa3818bc34ec5057f319d54036b6c640752cc1617c024a17515d1a6b2f945c2f48a3ab3d09ca0b7dd68ab9d097078d292cd4267e9c39f089a70faea351378c85563b11c8802bf44c383eccc0cf20cd39e55a9d31df4c766ee487eed4f528174e4425baab412ab2fd44400f1dab73046827567402f6ece195a73495139455b44ee4ead4bb1db3594b2a94b929fa51367179f0f4882adc00722dea6c6edb0798d3452a7fd60d858643ed8c2598c8297bf18227220efe2f948148a1851bbb515c72a47ce34cbbeec655133b0106781de0c9aa059f8f41f3200b19833148090c41870e1c465c528b9b73c1c2798a3a57b5c2c0cfe276de28b9f0b90027552b7e6375c085d35a0691f6ac7a7768c39351b2a4eabb54b8e0dba3486d2b597131b1f0b3553ab68cff9c15a9dec3adc83b0327b5764a645b3bbd7c77b2ce294f6a755cf4a278e473d7c1692b91a74e75d083a9b5d828596cb8218364a6175132eb4b782fe61202581d2b906ec926dcee4a2cd2302de6ec9354785ea52d5bd5900bda21ea652849adab4030243b676debdc60af83126d32d91c2d34a85341c20682e6d233ab41b8f02f154e6a05e4e9b897c2b319c990c52e3a859123b533d932bbdf76c276c527c2e4b21ceb4d8cd8aa8bb1b56dac6d90260d1b8db10c036bbaa54063abace4ba8ea2241c3da3f77980ddaa92bd2e7628c7629ab617f54c2527174b05a6ae8a8236da3229af186acd0293fea689c65e7716ccb0eb61a892b5e548eeca2475a55ec7d3d32658c78357533c329d62a2b5eda28a6cb492c93f3758e35524f9ac128236578e11276e742c286468aca330a42cf661ab98b783ebbd58643cafff27cf7b71c4685a678db575669c5f1543c3e0735af70bef07a975ec4a819b769132cbcc6379f1637c36f3278f7c7debe2cb1f7c7eadd434c8feb73fdd3bfaf4956223c0f1fcb4fec587792193fd4fee3cc31edc2956278e5f1fdd7cfc59566c1fbd39fc19d8d14999a138ee42707492b171f5c0afa848c877af9e78c7cb22f570ec3f77fb789951c882be4940930cf4f0d1db6fdc5f16528fe3ddaf0eee2fb324e3d8fb1e057942cd851ffef1fb8fc5fcd920f8af3f2e66c9fcffb84b7ff865b7ce875708c9ff60d8f137aa5a1fa900d00700001001010020742877c36a520b152b1337ea1ecd37b0c98ad07289c32fec392e7eebab9f0ac71f7bc8c718cfa75317b2e15702372a9222c4616783ee7b3f0ec6358f8c328eea00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72410000d00700001001010020058e23368b919493d6ac61d27f66b829a53893e88ddde857d3b82d913960960d22fa36f397752b98c295e3b31927f740127c0a99e76f8bfeea88f44466b8fbfd00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea990000d0070000100101001f43fe868e263d8134cf705aa85e26ce78ebb058edd558865fa3d240f5cb9e50c2389e9c8276eac800b7233a552045b2e79124c97e5156a0649849cc7f5d09eee600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000d0070000100101001f29e82b08ccf15e2187f29fea11ee3f4974f41b51e45b19f353348d8848b86fb71cadd88630456b7a1c60803c7b402487d41fbf18f0b0a13b4cca1f740447938300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000d0070000100101002047a8b784c3765b5c63ac52e3d8461b80bc2d3e3f62434f8accb277d9f2487cfd3c0728fcd26b5119a11288e5db46bc5b547877e220971609d1cef8cba443340800005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974280000d007000010010100203e701fbafd4149bc95b55a6bfc3b78246f5c2668ccc05ed4059a36ceb38f140b31e3b69e15f2579571e5bde39e034947271599c200e540b3949112bef163074c00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000d0070000100101001f0cc7352e60f4f8476783d6d1b48766a111c56fee2c1a552e76a75c92bc17de172f994ffc854c09717c904054819ca7a17379ddecaf531c439b35337ba099b81300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4050000d0070000100101002040965063a83be2d53b36c8d7e0775f503c2caa1407e586314562aace52c272fe60659e196413a6c9db4168470bcabb9a5851121c10c7b665f363f6cd4d1e4bda00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000d0070000100101002074ea7468b2a031c4cd53bf10ec3ac66b0c4b5c8779e045f1ef8d9c7b116be649217ff340107d0163397b99918ee2ce822b66cd6fce7b385af97a04671136e2ee00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0000d007000010010100204dfb21ca5140582379bc026792c16b4cf97827143a4a9cd99ae70b3e6016cd6316bcbb9f1cb1233f12a0bbcd9debafa64724d0459b5c8d3cb67ceddfb2e3962500005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d670000d0070000100101002033446a3a94ade71dff3edb786259679487ab701bbc147490b1d4159fecf545fa22fee0698db16bf616465e5cebb985bfc4d9ed1ec4a55e38997dd4b4bbc427eb00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c20000d0070000100101001f3f67edd35bf731a07f40c638e8812112cd7d1baa39ec7dac4a1b2f0c83ac8bd53689b56dba69a7386e3860a6f8976695ac0bc2b5dacae91080f1d54df2dac0c000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b44767070000d0070000100101001f1e030564013603d54f9e983b63cd940f8ff09ae038b14813f4021bb0c09ebb640d90cb4f8d57be2809f492a51737b671a5f549d4efa8e7efdaeaa9663c09d1ad00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450710000d007000010010100205cea642eecf05568ce8c5564e63349eea3b816108914ba2ab5efffbb8ea467265f0b6d474f03ed02a3bf529fd6e55a595cbf8dd1adf4311cb9c51e862f8a535400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000d0070000100101001f4556076cc86e0840bf69664f1ef8fcd4d91abda313d08e7840d24ba45cb429cf12b7d3a1f64250c19d1b975e7b107853beff70ebfc4c27c44f825dc05cdc9cd600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000d0070000100101001f354d903ad0f2c6cc9d9a377d681ffaa00475d1e559e48074b4c8cce3111d5c172903b2f179ad4d736dda4e7d1b6a859baeab9dde5e5e495ce09733ec4650634400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb400000d0070000100101001f1766fa716a828da244c9ce52919b7a19acb38dbd110d1bb0039bb2477c17e4465dceecb8330ed5ee9de1330930dfcfa1a5e8149ce8536a82c0093642adf7328200005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc0000d00700001001010020488923db1c78fa430a3a9eab75f4ee467c7b9a3d3b4eb3bd08e183c82ef79b9102a4d2a7d1ec79c96b404911ae1b10f579bd82a660011c1ca2b872b30ef7dcac00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000d0070000100101002031ca6aeda725c01ed6aa6199dd2767930803051d3bc2897956bc9f97f8db5abf3bf243b775b4020f0c96d8ad197d591d11f8a51760c19fdc81134eff06a1941f00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e880000d0070000100101001f03670020103e7843695b5c83b87d3183f9c0b21ee28f46ce80c061311835f436600f684f91df8e1e4a21233f1f97505a789189b4272a0d8bc2666891f93298e000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc000001 +DMLOG ACCEPTED_BLOCK 3 03000000030000000200000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010000000000012d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b0200000000000000010000000000ea305503000000010000000000ea305502000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df719023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000001f20041c84dfa3dc10503182e60706eeae02db7fbda81f47ea43d623f3dfd84c7b5e063a2ee30ba7f62984f4e87938e34e291f4425f7180ae676c8a02083f489970000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001010ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd0001023b3d4b0000000000ea305500000000000213588be25132b4167ced6df22b5439e376d5a20284190bb94a43e3e815c39c909387122a322a319e68e2a400273172919552ac6944509ba2ec812d1fde4254975a4ef4af4d3829f170281c6011578a9828a798eeaab84e11450c712e000000000000001f20041c84dfa3dc10503182e60706eeae02db7fbda81f47ea43d623f3dfd84c7b5e063a2ee30ba7f62984f4e87938e34e291f4425f7180ae676c8a02083f489971600d0070000fb05010100203b7de491b51d3d74624078bc2c5dc4420985f0350afb6923a5585b5621750c9f126d7cff0efeade2068c7b618fc754b2abb5bff8cdb9bd0ecb4432b72ae1ed380100a82f78daed5c7b8c5ce755ff1ef7357b67e3ebc6d94c3609f9e662d0b8a4659bb8eb2575dbbddbc476694b9cca2dfea3b0bbd99d647776bdbb9e1da70e0adead081045158a7894b6405524a4d21424545aa8cacb0d0815a94891fa20414284ff2a025511a245ad54737ee77cf7ceeccb71f09a87545b9e7be77b9cef7ce79cef3cbf71f44fe94f1bf5d03d9f1951f447e343fdf3d87be873f2879efef473830dea77fff59e7bbef7f440d3bfd197d9f57368d1bfa54767949ab11b9736d48cd9b8840f7a0b372ed11f35136cf0436fe80dfac0b80dbc2afa67f84d6306e6063201ad97a8ff9234d00880f033d54c84469e48cd68b03c8b3ea54dd0909531c1fc52d0b0ed95c70e2dae4f3fd29eed5de8b6a767e77a8b8fcdf6daf32a42d7cd6bdd76d9548e51317aeaedd5f5c5d5e9d9f5f576b7a72c9aa273ed73ebed9e4af025c3b4d595e9f9d9deecf4fae2cfb4558d9b09defcf4409f1a2aa7cead3d2e53ebddf6f90b8b40e6426f41a568ba89e04eaf75171f5b5c6e3f4ac8d519393476dbebab17ba73ede9e5c5738bbd75358c9e70f6e155c24ae17d44a6aeaeadaeb7e7f1327f61aedd5d5737a1d3a1f3e1e5d5b9a5b985d9c595e9b5d9eeecb9768ffae9756e8956e29db9475f6918efa23e77a1db6daff4a67b8be7daea00d316339982ed81b579743afff0f4238b2bf3d38be347558696da34d17361b9b778af3a88ef0707693c3db73adf56868958aed36dcfb5097257d61a2280580ef09890d1fac2ec3d6f1c57af61e4a877bdb74a6445ffcd681aa6a60b6bf3e02dda0ed993275414abb8369444511c0f0d594b9f517c8b1e31237624a07ff4371cd123d60e51efd0adb7da86ff63ab8f46725b10ea353d34145aad7434623774b17959a51baaf8d45f568fb8a6c3d9b5b5e5c7d5eb6a07b42a745a7bfdd83d47c727ee7bd39b87fe66539f0854767bbaa9b5dd3093f2d7a9078655417f5be683f4a5c81ecb752737e3f44d5a9f9cccad539d22ee1417cfe76a9c1a9c29b29e53ef1ad64e4faa62e3c4b0a9dbb45007e81ff5e90e663b4d2fe83d39aca9bdf8cdcb2a33ce1e489d4d8d4ac7b5def8415a6e29a755c64d9d66d262f59651832ba175dc6cd2f3ad0a40313352c533b4f3ffd03ada2854d3601718b7043ccf3b757258611fef0076d96d07d2ecce62649cc0127ae5968b8d4e1e38ddc96ecbb17da75c405b74f67c6e4ed034553cd1c92da19207457c3ed70f0c1b0c21ac685a71b19387d4d78c9c75da192c1c776901daf9131d02648088f62d173b2e62184ec68434c5f29bca465367881c84970c54f4d1c22c80549d0a2430a126fe9ede4b742b469a9637a28be0ed843e6191fd00d024d49de6bd366d0a5a6777d2dc74429b0dde36f5df9e6bec7a5859225a9339fce1c9dc60ae39a894d39e26292146a426345d7a93f272c2484b6b9e2e1154e1a0398c01a6a8778011febd839629d7b3d95d34d54c62415e4c31a2584ca6381a31acea26051d200bf4245168a23feb1ca6d5d2043cd2d9e1eda8f8f61f4e43950da9f42744a85e22fae9c3a08b2e5e0021137ecde82da8ded0adb2d78ef257a75be822622d65756a7949d1bae92fd774c0846b1104fa0872b354c43fcee7e5eb2cceaa08c0b2a62194695a9245a3dc961b6c411509c9112f456fcd80799088f838bb54d8415018cf5c23410b00c783082a10f50e84dded3abb44840118013088481f4a76fd881cda17441ad78fc81dfb8288bb7e440eef0b22adeb47e4ee7d4164ecfa1139ba2f884c5c3f22c7f70591cb6a174cf45e9898014c4c05e33982a10750d17ba2a2050223a0592d1118361ae9778cd51be612eb3957aa3975c4aadc4cb9a78eab14d660aa456f43fc36466f357e9ba03728426c01e32d8f870db33cdef01bc66b7ec378b62d9fc883fbd4017a0b8ae4b1fbd44dfc96d1db30bf35e8ad8e193c2eaec645d5b8b01a17f0fa0d5edf1c57b70aee99c7e5f60a97d10a97db2a5c1abc0b8cbbb9dae36baa3d1eacf69809ce8a9118e10581c42db234bd1d1264d57dea2e2107b5fd4035eece6adc1d6459c844b286602bf4adefd3fe7f92f6da533efd522076fd194daed5619535e0fa38f56e78155bff121a57aefcf1b77ee7d73ffde2d44f929380af57ae7cf6db5fc35720b9b9b9f9fca7fff04f3e72cf43c356be5efe95ef50ef43c3817cddfc230c7ef770e22c7c910f12ba05b9544fd1d3d923f6297dccb263414ecb8f8ed693d42f71e55b1f7e71ea3dbcc4339f7cf1c57ff8e047bef6f98d3ed0bfffbddfa0efef1e8e05ea3c3dc8c59e119833c76c4b409205c8de305a8f539ef639d94705e5437ffbf257805a244096e9419a6541802c1cb3ce03719decded17a94fab537bffde13e10c0fc28808402e4494c08c8c5f6fbdba4fd251e4ed2c9de385a0f531979861ee1b8392de34e1fb3137ed844273b365a0ffcb01e3da271b326c3d68ed9861fd6e8643f365ab77ed83be9118f9b5332ecd4313be98791a20538e3c73d013cc6cd451977f198cdfcb8ac931d1fad6b3fec7df4a88d9bb332ecec313be6878d75b2b78c52f891dd415f9ed190a6d7283eb3194e0bf99b27b324fdb2d131046c8ce4ab19389231e8eea0198a568f24ccc8823c7e4064cec5c507d8f58eb3db9a86d1a0a6039d62ed3cbbc37007e32c240f3f2848d65b2e98526010b5769ab010ae038f30f1b0e277b025f8f92fc012a09310635fd260540df077b6d2bce4647f5eea12572b34fae9bc53d4007b414c1f3719351cc2e45a47da98c714f14094031716fa8220d5eabc4ea926751db1ae09479bbacec3d7e6082462fb1461abca25c5157dde4507b51a2086c978c36344650a3d2378e671fa73468757a36d79743d753d30ed296b52d09ec5612f0283b22d4fd91dd44c795b25e102f218997a4c0750d45614c9842289d0ac0145dae9d3e6886dbd0245a283666f5a0cf7652e3b927edb50e84a24f9b8b911f2f6450ad6157d667654f6725c1e13781095c6095c40a756866653a3bc550e555cd032934211daf1045303a7069d09efb9ea4c8ed96760595ee05e97205a1662d29e4bb22a1c7fa6ae9359cfe89cb9c55d2f6881ee71268c99452f700b562d5b1a1523aec20199181db4bb70e1e346d870f3e0d1c79cac96feaa3511197562c7a6be91227a4a1e93f2382d8fb3c29aa3f218ab38045e819050a478bb8c2816e738036dbe496c7b2b734d58365171658c8f34c2d75d5846ebcdc8eced1c6b0d722c138e3564d24cae847bf4581304060ec559728fe871baa9f138454a891e93cda1abf069c8c125c2790976e1d4a6de7960ee4ebf6775c207e6867108142639236748b4227fcf8884fefb560ebe02cf66fa3cdbd4b229614a764ab856bb1ad78840bb706d53ced910b85613ae65c0d8d5ae81718cc54bb2c31a2ca4eaaf98418892b289d978cc2ec8db647f6dac54cd430309821d9c450e083949b2b45f31bbb673bbb9f7b9f5d2f05e4e35e586844ea48239adfc6095dd46019b2246227596a5a3900f24d5c897ec33dbed18927e2e14b3ff4db5b71e8e2b5d9c94ba38f1eb267d5d9c6c93aaa4b4fd7071f6949a44a4060a93c5252b46af76aa9f17f9a8ed38d5a72be161d1b986537d7a40386604cfb395626a99fbd91010518ab173cd9a77ad2db8572bbef6ec575ffbe030ab7ea44c3397c7d43ab6ec7d8b182e223fcef421e535c0d2a77032e9f85b56ebe8815339b682d93966a4d726348cef82e03b431009d0e9a53c06b221840833428f28fca9af13a231231a6e4174461ef38209a000d1b08f682888f2bc15993a2f324be42e6596e6cd88d6f1d0e22c4fa5fdf440fb99b23d19907119c6f957efacdd4fed792a6a1ab27f2015ce672d957a25426f3763619dfd083b3a2f3e074727ad952a33fd4598347de34ddae92d7af1ecdede06fb1ba52dfb22f46243ccbad8b2c957f040763767c99ee6ec2a0ec8cc80ffb1b6c5b5d8d59c5d456f95562cbc8a15bb8c8481bec479f2cb8a83576477103b2134297833766a03e859f16345c3e5014e2ce144f8fbe347e87338f7d17ff9cc37de40bccf5038390595c4d11069b50772d522cd826f2758303e7b993d600b7e247ed49492c8ee0436d4cac3615d2f87d4113d31a3127ecb3a651878d20f7e6058a7a20b8abb3b790492d3493b816202e9da850e1020c1715cd2e19ac0034c1412e8900b3329c7b818a4a038c326b5442e947a482ee11feb6eff967ecc4af4b0a93df57212ab2306e25629e6b054cca1e742d857cce136e90dbd62862e15511a70ca4eeda2a343d6d1c66ba3ad815acb1c45be8e75370825dac2727c717440afb364676ff3ca3de21e7a1b14e6ad2e40eca2bd1db718648f2a151f5d9be326fa1af179c04a964f23407ad373ff00fdbc66e20a9868a6e24b34d070054ab45329e15f30da6e38613b54129f42944b2cca25c1d2568a599fe40cc08a40086639cbca8bf9c04cb15c21c6dd3f90287bec23b44687a34186a6010df5a3dc6e83a6fb395d55ca871ec8e932b4f4dff50d2261b00709d51e2095b84c7b8084d0ecdfa6bf6e593346bcf1a069a6147c3bae9271dabb19d2f18e2ca7f470d0d4db7989efc2d471029d4b6e48579071e69a73cee2097b75459d7711f21379d4fbfd27096e54c49d664487980c1249ee79d2435ea9f20e12d9526d891c083a7af613b97950aaaa2e5ecadeeb7bcb8de5c949d699d0facebc0b03a983cc81613726c1eee85b728274a564f0835229d2eeb4f5cbd2495adaa14e7857b52a5bc14dd007466aba21a8e469a2b7d124d84a934068120dd224649a18a189014d42170dd0049ed95b0cb248f5bedcb868a9703bd0447291c8da1c40b3e93940be207c54a4a6b886bc7b117510e2401155977b7f1545d441506511065af8da8aa8bb2162b13bfbaa8ba8af0e9143fb8248e3fa11b9635f1071d78fc8e17d41a475fd88dcbd2f888c5d3f2247f7059189eb47e4f8be20b27b11752f4caeb188ba072aba84b05b11f5b7c52f0ff7d1fa243badcfa0a68d5cb2cdfa88ed89c5ba180a3b617822313ce4122f650f55db492aa32ac3c5b925e55d591f52c61c4103346f04d4499660a128307e701712259ca6a0686e2bb738620389fe53f74397cc27502417c677740825f24bab6b48755e104ec1521e88c7b8f1ce61d6e6e46052e81dba402e3489b3cf8fa03f5130266727d7127d87f065450042870b65e4efa896783641cea40b386e534211cd496d89d4789ce65d6a7642602ea55261d877e1a00417a5b0469efa6b46c81821b6fe0b6b62899edd12a79ce47a13416de4108f3b1855443db8d34456556e6d69dc1c433585c2a0f0a4bfcf147074c48d4027e4ea1c9132aceea269dcb2cb0ee54c30d0ed0301b22bf0edfa910ba49183f2e21b12d20588700a0d3bcc63b343a374ba98ce0a914bc8ac629a6cad8684a5810d61c3622925253cf062a7b86bcbd8d82585e3b1a0d551445308dce98108b526112af5d4ab6b75779010321fe9dd61c70f725aa32665158d143697eb10a2b01cc41c82e32d92405471e94a3e90612401c97eca45083c25b8268fb4d1d41e0ce8076632174bd2a67fa5ad2106a2649c079c11d2888b9504c57fc69b03ba4896dcfc1037be2c3b66998e24f0e18f983d667203d9e6e771760b4d8c789c4cfcd873c20fe2dfe94e19df97c5a6b314ac09050981a3ac1d5bd9ad0c0195f7337251b13375c94553fa09faf8d9f7de4e6c232e51b0fa5d4d7e93d4cd82c39c1c3a46b84cf2da25da4ffb1217d21d874a0a071c1712754422ac5c05e864ef1b958188092d5f02909091a01ecd43cf46f60724b28fd9aa7b26c6583e41264cea100a706249b344b44b6622b49296b48eeb94c50a30904f218e9b5c4f844a75c8b130982d4c948a59fa211b0a0b858d14ae8b0ae228c9ee0c4228a4b96bb72004210dc270e5d930600b1c3026c54f683635ab00d6fa688af860cb443a244c1583c0389a4a7e01d9bc3728f5641e4c4d3cf524498b2e363ad80cf5b1f9206340d0ab2081149a08de95e7fc098c40c9b084430c670cf840c2c30f80c1001c72a3194cc61aa744850e3d04b1b03d3ab8d9413ec822bd068f000b0550d7b21ea77848e6d0820405be34e44ba3c3bb979b21d294f9a6ac6c324898105f3eef85321bd08c03a944affa37399518f854a264b612a46b78e9665837e93605c7df919d97b17e9c682fbe3dbc5d7dd9d216f910179773b795c36d3596d57b7a3f85d95244a87095c41ae3ab3cbe7a2fd4522e197c1fc80d02f26553a9bb6d92b5975c9529ea3da1226175581e8e9d003afca4be5a223c8d1dd6b1ca4d86d089879b7c07a5515d1e6079e220f730fc4f674e6e99ea7c4a6fcbec5b315b97b3f59eb3ab0923db26f00ea026b3fed1701dc9cabe6d5492748924e97c0ed7882d6435fae7b86830703b4af160f1a12cd9b407799af2ae171cad3c821f620a5c698a59f511d988b0c5f7a8016e3f291dc2ab0777d1456fbf1dd503b80a996be23700e23d231d6c71ef05b7b3011d3bf7fefb062960728e82342d8b6b900cc5e50dbec311c38292e1586a4afa350f91f328e15902d5b4151ce636bcf6509cd8a85526bf902f5e62d5e00b4f7cc58ebdddca313462bd02c9e921b5ca387a6374204d9fd7261057f07f5de10d68ba6d6a8ec28b4a668ed804fecbeb540c5394c5d81d5f712a95e0a70ced28d8eedc5edb8e1a7e478d6bd851c38f7ba51d855e77e73bb7c585403f322b4766db062503831a25811a7bd801efdd8148311e194556f468346b4cab1ae221176535ef4aa65ff6d6eed590ea1a69b4cfc4317b11a74ca76571b9a9bfb6b2295454fcae08e7607b2565b3aaa404a2baab4a4a807d04be9262717acec8035703032e989c159d754a640147f079ae90f81a37d0872a65dff3ac04ce72a710f181af81841c78579d196a20b6ac8184acb2b8936f32c9302e78707dade56f56a20632263d6b825352ba0e16c569cb65eec0578e41c4c1dab154bf387e0dfaa5635b2e17c0a3adc0700c2faa861597e8700e1ffad5e320f5fa3b9b280b2c81e86e0616488598c1f5dbefe7769ac8451714c7a02d898f57d1edb4a36dea1dc96dafe17d65bcf82a3dd99b868e47bf293ef9d5676f19d0f2b401d6f296b53c59956552f441a5e80df39698a53c4dfd83ec68f9e6aab746f596f937291396399eb1dd6d848574f66d44c0587438c5cd2ca9ec036cf37f0b0de3ebb0c8d80d9a1672b079a95dac8b45a2e2f439ee36e2e48b8db192b550550564771bc377292cdb98a735bb4ffca3a5fdf47ccec8e3b4f77ce450ca314cf8d69fe8047a3f22878e20fcdaff19f79e7434a3c746ebefac0dca7bf7dfbc36328542a6edb820b046600432719855c908c5604614532916a51dc32363fdba353d22d40c25b264e141fc88e82de6f851fa0349af1889da620490914b38808c3880440e860248c3c16513f65ae35786fd00d2ec08206309203d9c12f92a808ca6b80254c19100d29401a447c5226ea72f6500697d00197b3be92355e5d713a3238999b16dc1a2646ac606e245d6be134c3ebc8d41b32bcfd0ec6ed1e3c48a97becfd8ffff8cf51750b65c46aa38fcb211ed36e06ddc30edc657387689ea5ae68c04575f54db8239f95583c21d259e3d51a9c80984574c3ab62bd2debfb351fa2b49df5f09d88a559dc9167f25e0247f69659ca9fc9586f82b6ec05f69f5fd9506dfb13c25f8bc593c83898168ef7819edb16790fea93656c29531b92dc3e9b631e7adb35c01e3727499d6e15008d849b3385d64ef9638319907d92dcef6af04245d64f6d8be210d990cdc472248b8432a9797f8f46523e3e668992de55ca7de35d729a1aa53e9b3b8ea53ba3241e5b634cec1ad82dbf229f257908c2c9ec50b0e635956966141f1157268c47b09e0bdc470e7254625ff212e1ae2bd9832f41c702bb4fca25bfb4b4174e61acb79826461243f15364c32fc34462ea121730a88b0635c868d7c0e5c2e0918c13f3ec1ee2049d102d7fe49ea16fc85002be94fc0ae8acafc3b702f455adcf7b5f2e46906e10294915cc077a9785d5d9574627f8904bb8a21f13edb8a7ed9063b20a15ccd22152117b762a0148b24c4e5c5ad7e469696ab344d799b2b4dffd1a6fc93fef49d8fcc2e2eb7e75d6fd5cd2e2fafcecdf6da6e6df6d1f6ba5a7db8d39eebd197f575e95fecb5bbb3bdd5ee34ded7ddca6acf2daeb87317967b8bd38b2bf3ed8b8a7f0c99def9fe2e0d55ed6e77b5ebf07f5b2cae3c5a4d567cacd310ed8a33e0e9bd73b32b0036476db4baacbb0ed8bdd98797a9e111374bfd0bedae9b5b5de97567e77a8aeb00e9eb77e0786e757ef191c7f744efe581e5fcd06b5cee63cfa9f44df21f4350bb47786176e551225777f1dc6cf771b7d47edcbd7fa1bde22163d7b32b1ebe62cd9ae66bddd5deeadceab2f3ff71488969ffff18e132651a3cdac61cb22ce9dd1756da17d70806ed50684aa83eb278b13d3ffdf0e3bdf63ab05cef752fcc097569ee1f349552ff05ee7357f400d00700008101010100204b21f3cba072cc493e70861540df4677b498b0505a8b8e2a346b85a0c2dd2fc4263c4a7d8629026c4eb594ad96fac2bfe5f8ffebb9c841c353920b7b8ec11abc0100d90778da8d563b8f1c4510eedbf7e37cf209d9e60808402496c0dcdaac4e8ece01090112afe83043ef74ed4e6b677a86ee9edd5b3b2121b049888d842c84c0c1456702eb20b036424242c2e00408800c24fe03d53db3f33a58e860b6bbeaebeaeaaaafaab7f55bff9d1a796df0e5798263c37cc89f2fbe657e1eb8c7cb92e0de5f83c1eded95e4fded2d08150faf5ea5237e69f7855db2d3c199e351e5915a339c0b900d4103681849dff5c09daa3818bc34ec5057f319d54036b6c640752cc1617c024a17515d1a6b2f945c2f48a3ab3d09ca0b7dd68ab9d097078d292cd4267e9c39f089a70faea351378c85563b11c8802bf44c383eccc0cf20cd39e55a9d31df4c766ee487eed4f528174e4425baab412ab2fd44400f1dab73046827567402f6ece195a73495139455b44ee4ead4bb1db3594b2a94b929fa51367179f0f4882adc00722dea6c6edb0798d3452a7fd60d858643ed8c2598c8297bf18227220efe2f948148a1851bbb515c72a47ce34cbbeec655133b0106781de0c9aa059f8f41f3200b19833148090c41870e1c465c528b9b73c1c2798a3a57b5c2c0cfe276de28b9f0b90027552b7e6375c085d35a0691f6ac7a7768c39351b2a4eabb54b8e0dba3486d2b597131b1f0b3553ab68cff9c15a9dec3adc83b0327b5764a645b3bbd7c77b2ce294f6a755cf4a278e473d7c1692b91a74e75d083a9b5d828596cb8218364a6175132eb4b782fe61202581d2b906ec926dcee4a2cd2302de6ec9354785ea52d5bd5900bda21ea652849adab4030243b676debdc60af83126d32d91c2d34a85341c20682e6d233ab41b8f02f154e6a05e4e9b897c2b319c990c52e3a859123b533d932bbdf76c276c527c2e4b21ceb4d8cd8aa8bb1b56dac6d90260d1b8db10c036bbaa54063abace4ba8ea2241c3da3f77980ddaa92bd2e7628c7629ab617f54c2527174b05a6ae8a8236da3229af186acd0293fea689c65e7716ccb0eb61a892b5e548eeca2475a55ec7d3d32658c78357533c329d62a2b5eda28a6cb492c93f3758e35524f9ac128236578e11276e742c286468aca330a42cf661ab98b783ebbd58643cafff27cf7b71c4685a678db575669c5f1543c3e0735af70bef07a975ec4a819b769132cbcc6379f1637c36f3278f7c7debe2cb1f7c7eadd434c8feb73fdd3bfaf4956223c0f1fcb4fec587792193fd4fee3cc31edc2956278e5f1fdd7cfc59566c1fbd39fc19d8d14999a138ee42707492b171f5c0afa848c877af9e78c7cb22f570ec3f77fb789951c882be4940930cf4f0d1db6fdc5f16528fe3ddaf0eee2fb324e3d8fb1e057942cd851ffef1fb8fc5fcd920f8af3f2e66c9fcffb84b7ff865b7ce875708c9ff60d8f137aa5a1fa900d00700001001010020742877c36a520b152b1337ea1ecd37b0c98ad07289c32fec392e7eebab9f0ac71f7bc8c718cfa75317b2e15702372a9222c4616783ee7b3f0ec6358f8c328eea00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232201a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72410000d00700001001010020058e23368b919493d6ac61d27f66b829a53893e88ddde857d3b82d913960960d22fa36f397752b98c295e3b31927f740127c0a99e76f8bfeea88f44466b8fbfd00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea990000d0070000100101001f43fe868e263d8134cf705aa85e26ce78ebb058edd558865fa3d240f5cb9e50c2389e9c8276eac800b7233a552045b2e79124c97e5156a0649849cc7f5d09eee600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f0000d0070000100101001f29e82b08ccf15e2187f29fea11ee3f4974f41b51e45b19f353348d8848b86fb71cadd88630456b7a1c60803c7b402487d41fbf18f0b0a13b4cca1f740447938300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff5260000d0070000100101002047a8b784c3765b5c63ac52e3d8461b80bc2d3e3f62434f8accb277d9f2487cfd3c0728fcd26b5119a11288e5db46bc5b547877e220971609d1cef8cba443340800005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322068dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974280000d007000010010100203e701fbafd4149bc95b55a6bfc3b78246f5c2668ccc05ed4059a36ceb38f140b31e3b69e15f2579571e5bde39e034947271599c200e540b3949112bef163074c00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c430000d0070000100101001f0cc7352e60f4f8476783d6d1b48766a111c56fee2c1a552e76a75c92bc17de172f994ffc854c09717c904054819ca7a17379ddecaf531c439b35337ba099b81300005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232208ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4050000d0070000100101002040965063a83be2d53b36c8d7e0775f503c2caa1407e586314562aace52c272fe60659e196413a6c9db4168470bcabb9a5851121c10c7b665f363f6cd4d1e4bda00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232202652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed250000d0070000100101002074ea7468b2a031c4cd53bf10ec3ac66b0c4b5c8779e045f1ef8d9c7b116be649217ff340107d0163397b99918ee2ce822b66cd6fce7b385af97a04671136e2ee00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0000d007000010010100204dfb21ca5140582379bc026792c16b4cf97827143a4a9cd99ae70b3e6016cd6316bcbb9f1cb1233f12a0bbcd9debafa64724d0459b5c8d3cb67ceddfb2e3962500005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d670000d0070000100101002033446a3a94ade71dff3edb786259679487ab701bbc147490b1d4159fecf545fa22fee0698db16bf616465e5cebb985bfc4d9ed1ec4a55e38997dd4b4bbc427eb00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232204fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c20000d0070000100101001f3f67edd35bf731a07f40c638e8812112cd7d1baa39ec7dac4a1b2f0c83ac8bd53689b56dba69a7386e3860a6f8976695ac0bc2b5dacae91080f1d54df2dac0c000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b44767070000d0070000100101001f1e030564013603d54f9e983b63cd940f8ff09ae038b14813f4021bb0c09ebb640d90cb4f8d57be2809f492a51737b671a5f549d4efa8e7efdaeaa9663c09d1ad00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450710000d007000010010100205cea642eecf05568ce8c5564e63349eea3b816108914ba2ab5efffbb8ea467265f0b6d474f03ed02a3bf529fd6e55a595cbf8dd1adf4311cb9c51e862f8a535400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232205443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b40000d0070000100101001f4556076cc86e0840bf69664f1ef8fcd4d91abda313d08e7840d24ba45cb429cf12b7d3a1f64250c19d1b975e7b107853beff70ebfc4c27c44f825dc05cdc9cd600005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e990000d0070000100101001f354d903ad0f2c6cc9d9a377d681ffaa00475d1e559e48074b4c8cce3111d5c172903b2f179ad4d736dda4e7d1b6a859baeab9dde5e5e495ce09733ec4650634400005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb400000d0070000100101001f1766fa716a828da244c9ce52919b7a19acb38dbd110d1bb0039bb2477c17e4465dceecb8330ed5ee9de1330930dfcfa1a5e8149ce8536a82c0093642adf7328200005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed3232206bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc0000d00700001001010020488923db1c78fa430a3a9eab75f4ee467c7b9a3d3b4eb3bd08e183c82ef79b9102a4d2a7d1ec79c96b404911ae1b10f579bd82a660011c1ca2b872b30ef7dcac00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322035c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b0000d0070000100101002031ca6aeda725c01ed6aa6199dd2767930803051d3bc2897956bc9f97f8db5abf3bf243b775b4020f0c96d8ad197d591d11f8a51760c19fdc81134eff06a1941f00005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed32322098c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e880000d0070000100101001f03670020103e7843695b5c83b87d3183f9c0b21ee28f46ce80c061311835f436600f684f91df8e1e4a21233f1f97505a789189b4272a0d8bc2666891f93298e000005206e10b5e02005132b41600000000010000000000ea30550000002a9bed3232010000000000ea305500000000a8ed323220a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc000001 DMLOG START_BLOCK 4 DMLOG FEATURE_OP ACTIVATE 1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241 {"feature_digest":"1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"f3c3d91c4603cde2397268bfed4e662465293aab10cd9416db0d442b8cec2949","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"ONLY_LINK_TO_EXISTING_PERMISSION"}]} DMLOG FEATURE_OP ACTIVATE ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99 {"feature_digest":"ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99","subjective_restrictions":{"enabled":true,"preactivation_required":true,"earliest_allowed_activation_time":"1970-01-01T00:00:00.000"},"description_digest":"9908b3f8413c8474ab2a6be149d3f4f6d0421d37886033f27d4759c47a26d944","dependencies":[],"protocol_feature_type":"builtin","specification":[{"name":"builtin_feature_codename","value":"REPLACE_DEFERRED"}]} @@ -166,7 +166,7 @@ DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1 DMLOG APPLIED_TRANSACTION 4 5ade57480d2e64fb49dd5d8303b08ecff6499745f854b8e70dff5f00cc1c060b04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e50100d00700008301000000000000000018040000000000000001010000010000000000ea30552deb8b0eef2f2bfd027d20727a96e4b30eb6ccdc27488670d57bf488395c48fc1b000000000000001b00000000000000010000000000ea30551b0000000000000002020000000000ea30550000000000ea305500000000b863b2c2010000000000ea305500000000a8ed323293120000000000ea305589120e656f73696f3a3a6162692f312e320117626c6f636b5f7369676e696e675f617574686f726974792276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f763019086162695f686173680002056f776e6572046e616d6504686173680b636865636b73756d32353608616374697661746500010e666561747572655f6469676573740b636865636b73756d32353609617574686f726974790004097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d086163636f756e7473197065726d697373696f6e5f6c6576656c5f7765696768745b5d0577616974730d776169745f7765696768745b5d1a626c6f636b5f7369676e696e675f617574686f726974795f76300002097468726573686f6c640675696e743332046b6579730c6b65795f7765696768745b5d15626c6f636b636861696e5f706172616d65746572730011136d61785f626c6f636b5f6e65745f75736167650675696e7436341a7461726765745f626c6f636b5f6e65745f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6e65745f75736167650675696e7433321e626173655f7065725f7472616e73616374696f6e5f6e65745f75736167650675696e743332106e65745f75736167655f6c65657761790675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f6e756d0675696e74333223636f6e746578745f667265655f646973636f756e745f6e65745f75736167655f64656e0675696e743332136d61785f626c6f636b5f6370755f75736167650675696e7433321a7461726765745f626c6f636b5f6370755f75736167655f7063740675696e743332196d61785f7472616e73616374696f6e5f6370755f75736167650675696e743332196d696e5f7472616e73616374696f6e5f6370755f75736167650675696e743332186d61785f7472616e73616374696f6e5f6c69666574696d650675696e7433321e64656665727265645f7472785f65787069726174696f6e5f77696e646f770675696e743332156d61785f7472616e73616374696f6e5f64656c61790675696e743332166d61785f696e6c696e655f616374696f6e5f73697a650675696e743332176d61785f696e6c696e655f616374696f6e5f64657074680675696e743136136d61785f617574686f726974795f64657074680675696e7431360b63616e63656c64656c617900020e63616e63656c696e675f61757468107065726d697373696f6e5f6c6576656c067472785f69640b636865636b73756d3235360a64656c657465617574680002076163636f756e74046e616d650a7065726d697373696f6e046e616d650a6b65795f7765696768740002036b65790a7075626c69635f6b6579067765696768740675696e743136086c696e6b617574680004076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650b726571756972656d656e74046e616d650a6e65776163636f756e7400040763726561746f72046e616d65046e616d65046e616d65056f776e657209617574686f726974790661637469766509617574686f72697479076f6e6572726f7200020973656e6465725f69640775696e743132380873656e745f747278056279746573107065726d697373696f6e5f6c6576656c0002056163746f72046e616d650a7065726d697373696f6e046e616d65177065726d697373696f6e5f6c6576656c5f77656967687400020a7065726d697373696f6e107065726d697373696f6e5f6c6576656c067765696768740675696e7431361270726f64756365725f617574686f7269747900020d70726f64756365725f6e616d65046e616d6509617574686f7269747917626c6f636b5f7369676e696e675f617574686f726974790c72657161637469766174656400010e666561747572655f6469676573740b636865636b73756d323536077265716175746800010466726f6d046e616d65067365746162690002076163636f756e74046e616d65036162690562797465730a736574616c696d6974730004076163636f756e74046e616d650972616d5f627974657305696e7436340a6e65745f77656967687405696e7436340a6370755f77656967687405696e74363407736574636f64650004076163636f756e74046e616d6506766d747970650575696e743809766d76657273696f6e0575696e743804636f646505627974657309736574706172616d73000106706172616d7315626c6f636b636861696e5f706172616d657465727307736574707269760002076163636f756e74046e616d650769735f707269760575696e74380873657470726f64730001087363686564756c651470726f64756365725f617574686f726974795b5d0a756e6c696e6b617574680003076163636f756e74046e616d6504636f6465046e616d650474797065046e616d650a757064617465617574680004076163636f756e74046e616d650a7065726d697373696f6e046e616d6506706172656e74046e616d65046175746809617574686f726974790b776169745f776569676874000208776169745f7365630675696e743332067765696768740675696e743136100000002a9bed32320861637469766174650000bc892a4585a6410b63616e63656c64656c6179000040cbdaa8aca24a0a64656c65746561757468000000002d6b03a78b086c696e6b617574680000409e9a2264b89a0a6e65776163636f756e7400000000e0d27bd5a4076f6e6572726f7200905436db6564acba0c72657161637469766174656400000000a0656dacba07726571617574680000000000b863b2c206736574616269000000ce4eba68b2c20a736574616c696d6974730000000040258ab2c207736574636f6465000000c0d25c53b3c209736574706172616d730000000060bb5bb3c207736574707269760000000038d15bb3c20873657470726f6473000040cbdac0e9e2d40a756e6c696e6b61757468000040cbdaa86c52d50a757064617465617574680001000000a061d3dc31036936340000086162695f68617368000000012276617269616e745f626c6f636b5f7369676e696e675f617574686f726974795f7630011a626c6f636b5f7369676e696e675f617574686f726974795f763000000000000000000000005ade57480d2e64fb49dd5d8303b08ecff6499745f854b8e70dff5f00cc1c060b04000000033b3d4b0100000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e5010000000000ea3055890000000000000000000000000000 DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":3,"value_ex":80800000,"consumed":9696},"average_block_cpu_usage":{"last_ordinal":3,"value_ex":368326389,"consumed":44101},"pending_net_usage":7928,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1050675,"virtual_cpu_limit":200400} DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":146193333,"consumed":8009},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":399423669,"consumed":4466},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} -DMLOG ACCEPTED_BLOCK 4 04000000040000000300000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000300000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7192d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b5a5902476311cae3e60a34f4b68b4336275d05d6835128c04ba783367af61f050300000000000000010000000000ea305504000000010000000000ea305503000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e5033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc002011cfaa913847cc0153220aaca619114879a97d55942af073d83a71fd044ede7257cda33f044c154d10a137e48e9862e00bf114268cc46b3eef3a622c7fd6c3a20000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001150ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fccad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc002011cfaa913847cc0153220aaca619114879a97d55942af073d83a71fd044ede7257cda33f044c154d10a137e48e9862e00bf114268cc46b3eef3a622c7fd6c3a20200d0070000dc060101001f00e74c5607ebe92350dc791bb2cb65c8ceb52fe6623104137f710805b93a84e23a3530fea5cea3743b77736669d4962f0be8dbe1bede210eb1c2460924b505a60100af3578daed3c0b8c5c5775f7f33eb3f366ece7609261ed36771e4b3aa64ed90467bd3569e3b725fe902f69a0f4c77abc3bf6ceecd7b3b3c6aea8c734566a3e95684b4b12aa1650da90d05029204441544e4a24a0544d2141a42a2dad2a15416953552a1451d2f3b9f7cd9bd9dde03049402a9b78e7befbee39f7def33fe7ded9f09fa2376a717edfe73e21e047e22ff1b5f1d7c1effd2f7bdb438fe43bc407be71f5d57f7577aeeb2fe0a1beba883df22ef99223421c51ddae38a2bbf8db3b033fb27b44c83347bcee9933d0e577f107fa347fa8ecf719fb4e1c09108cfae519c077c66102b46768a0841ed925c4080b2f003b4dcba3ba04c2c814f4a8a7fc31dd583a19cd1e9d3ed65c9a9d6e4eec111a7b4a8de5d5e6f2747d75b5d1ee08895df1cc5abbdd58ea4cb71b338de6c9465b78d8edd78f2ec31081ed328f9f5e9dab5f7dcd845084bbd77715f7e4465d73d5d5dc17dbbe7673a5b1387bd5c4387707794c23d3b09eb9854ef395c2c767af8732c8e31a194012c1829761bdd3f38dd322c01eb3dae84c1f5d589e999f99ab3797a657eaedfa62a3d368af427366be31cb3b0e161b8b332ba7454830c7bf174c01875d8aa857dacb2bcbab8d596cccaecdc0183142547524ec34171b4cbeed88b63ed30182e64613aac24abbb9d4599d5ee0d55ce24894db4d91b002f7563bcbed06b12fa2ae76e3c45a137aea6b9d3951c2ae2dbcb0e6c9e642e338acb68c9d2fc2ce76637579ad3dd3985e682e363bab620bbe79c9c6fb986e9c125b0972a5dda065d73b8de9638d7a67addd1031518d97cd0fdb9babeeedb41b3e2bb631cbe17979697ab6dea94faf367fad212ea16ec03b3b9d7bc7c4d89617c8e999e5d9867811f61761f34842dc3af1a90c1d6b2bb3b82cecdbdea3e41cac5dea03d78b176f8bc5b6388e4b7141c5971654e132296359e19f82b41fb252c04f5180a674ff54411614fc143c5faec872d9d752c8e052dd95e9d90b22ea8af49f1fcd3ec211e9d75756164e8b978d5c22452aa3d2eb5eff0bbff84bbffcab6f9c9e6d1c2b7ef0edf27a4fc4b5e8cb5a18115f198f1961e46bbdfd5367cffecfe3f79fbbfbefefe91a05cfd81dbfca87ee07bff85bbff79efb5fd7ebbdd6f57ef06f3f2b7add3f83dd67bffad0372e7ce1ed391c3f6b477fece3ff797baff73ae8fdd69f3cfef90fbcef0b0fe770ec271c671fffd4fb9f9ceaf5a6dc7bf69b77e57b5fcdbd1ffaf63f7ceddedc7cd773f747bff9c5fce003d8fbb1ffbef7ddf7e47b0fd2d80bbffbedbeb187a8f7f7fffaeb8fe77b6f64bc7ff7a7eff9e2c773d3dd4cdd8f3df4e14fdc7d75aff7167fea9df73ff9e497df7177dfe05b7d23782b173e7ed713e2366f7f4acf4f7ee1c3dff88dff10b189067ffcdc70c7a7be3d0382b7f42348457c55d496baab60d2b248c556e84a454dbd039ed3f864225b899a8027ee3db73fd146b4d2adad74e5442226a00300551a778cb801c1a12d5b38de4868546504afe57e91760fe2dbf49d17442c23a32325a20929bb2f8539e6137833a14a000c33946a4af4d09fdd8fbd384d2aae1388377aa5545d589a34624755aafd1af0c75724a22c5351e535a689babe2c8dda2644494491115180e2fb13910f3a2fecef222e56ecd5e7d3e8665ec857c47c22c78070b0f42f09d844819a31b4bcac85af45fc8a517a34b286af60c5f3f116e8f98a688d89e8fd05582192b30618e09797a8f9347c0defff61d83f7556556414c014e2ada38676eea505a2b587bdadaa7628005a6f0cad532f07ed65d0a5a1a0e3a1a0b70f055d190a7ae750d06628e8b1a1a06b4341ef1e0a7a7c28e83d43414f0e057ded50d017443fb8dc0c5ce5c05506fe0880cbef0d2e07c0115844df965a76d519b23be3f38926b38373c5adb83025aa5e1a57d1a02968fb60e2f08551ad6aa0d0de02cec36561fca9c29dc633c155429c4bbca9c9f3e7aa3ebcebc2ba8c07efaa5e89ed6f2a0fd0daee67eb0b907b35982607bb570b9c0eed7dab2a70769c3522539ea8d480e9663431a0e94daf011ee7d39df4542b1e8135165abb34401a8d1f1e4ee4edc5c881e603ab0fa206f6114cffbb212c817cc0c3ed3f2578ff1a1410fd00b4a6c02e57e0a3bb57c7308d007489874bd6849068e0c116d1bbddf36f1ff9f7abc00508f42287687d0011bf32017a8f1bcd1bbff008bb1d03bc1bc7f7b496780fd3c78bd56b69d8dbfe12878160c4bb12818b888126b556e2631bf6012b4c02d7aeb492d0b68d46b4c0427c42cc46814f480af8e199c27c3c0e84c27e0082bde0a8809f63f71c22d1262db65d7a9c774e636a203373f661421de109043b0e3ba4d09e50b3d00407445c8caf19653c853c8d2c212dd6f8d2c49f507b88943032be1d593a7506c82adf0cbf7efdf53b600d48334193665c40fa01e06ee282aea99d89c20f730bc02b7c13c307732b25506598ab204f15d8c0ce1272029a76bdb41d0d362c9e8810d191aa7090e2fa323aee97473c5325f1af2f8bdebc205707510daa02506a8c57e65ac876501b4321050a83421c0a70000b044a3261aae2272e7627e187099f22df7d2ed0234e2f311e505558f618cf297005a0bce06690bb3e29034ceb83f8d7303038004107a804ae02175652107bc0f3015c2374e2c2029238fe0f5407561957133fedb2edf82f1453248f9fbec53b5cc6467c45354c65b580bd405d8e8ce693700cc65741a724488e1f5747596803165a2ba301127edc04406bdb0102ec5a356e295c7f48a15bfae4a7484b0213b270851886788a77985ede3708e5bf3a0278c06414817c604c8d971a0003db118139f149a1ab2a657352222346a35ad5326ddf673352422b16993259b188ac5809de8115f34d84562c622df59d15fbe8a3b402654a2864cac1b215f331186d91dd8c705ae0005a312fb362beb362767ab45a8002a7ec1932524b58066a5035c2b922a41a4f199922be30d853446878a8f10309b5c9a97911ed3675c53dcd97a076207dc18432f8817a05e8d16ec19b9d4ed676263e591c101b542d1f5fc6f01165aa65e02940d542f9ca546b84e6b3c4d620aca05780b1807a1042104cca4aec6114d8efb30e50fc6a82e82ea5159867d20203d6b90a16628c2c3fda54c16cf824194bb53f56641ad8827e9d3a8d643fe0b11da45f011bc3008d21c63bc0978c4a187bc173dc7b06427a407b7ac016893585a60a594713f08c7fc8f2a8d35b5be446d0bcd52878f7d02ca3ddb141b647bc46ff0beb420b09bbd9338512508b13c22aac191460067d34837e66064180d03e7c5ef7fc3650064c03b978da49a2af1597714c4f8fde94397fadd0680da76ad052d41a8796a4d624b4105cd3b81761eb3eb0058593fbc4a5a4eb31b45e4cad0ab4b623100cd82742eac3714136cecfc679b8049e7ff24e9cfa4ece0acf5e785adc710e3a2ab6e32bd7dd4161023d3d75f91de7f065e13c3e7e6b2bbeaa60fb3b2101d5a0fd5d7d072dfbdcb973ac79304dfc3c4f53210221d1b6510b097909b5907c715f9a25e7d3cbd9909e7f240bc2501ac126985c1066480814711462b17bb4f4bbd624e37bfc05d49b4f2b8bc00e301e41fac1271e7802b5307d001bd5d08d0521a3615efaf8034fbc1c0c246837d89b4e1282590e0eef48425c0e587041b11858d4ca42bc0b432349de005d00ca287a8dca4202f99f44f514a8e9b06a927bcc42031e84e02d8af1c0f80636b7e4e586ec7c0a2d703455a931270737e4e12c1034f12c921502e5135eaf406c97e91b4697d04d53e3f31cc590e04743e391d3a4292d49439a12760401ae8877c3db90a33d1fd54ee06a3d8c86d80103063018b0a21057142224382de79e259a1f89e607b687335140869d1e74468f29ed394b1493bea5b821f2ee3015b8308525075e359283d3f1c49f4ffdb507ab01791d09713ef8c4f03cfac7db70378a286179eebb052a6b20d024600a4d569588fb8c98d237134c98760f9495454dda586ac5af1d251348b82078f42d35897ebea526901136e5a39c808cc4b78988431cf4ece0e96f2a534c68c2f9f8e72c20455026bc85de802547798e38f8f2f8031780d8914aa0a7f1cf8f925f040bf6675aa105ebd92f34def165cfb11913991913991913793326d88c89cc8c89cc8c89ff7f660cfcd18ef4939039ee045efd74fa096ab1818afea0dfe570854a585e29e4153e32afb4e595b453286a31afa49d8c324dcb2b68dd07c68b7925d10513afb0c5bc92c84c0f79857dcc2b37cecfc6792eb7d048443d4844dd4744dd4f449d23a2ce11516744d43d5ed134f1f33c4d8508c4bcc216f30a5bcc2b8856e29752cc02dcb9ef4701c10f5b40a0e21fa320e04b0f739ec08cfa73293de7457a491d84af3f9e78655b732860c5859c00d958ae33a467bdc3e48eaea82acec23c978501127a8e2f1fb5082c300c819c4a46bd7c09f312ced83901436f4bb1ac979e3a91160ee6732b9d8d6593fd6aa961e5b86c5eae4b822f72691106ef3f42b20192cf289689f13e9960894051789632600b4c63fc81b91df4b7b0ca52b3352dc295cfb631daab6132565363582fa4ba88e33e0909961bc7284a51079f09ee3284930e4e3e039c05b8740080169e52e899c932e59185563c35ca35974242e514da5f89ab2ab6a8f7b4b4153d5bfa84dc5b63d4abe97c8862e5c3b48c3b1eedab8f5e292810e22553e088a1d2d3e20410ea697922519d07cf216bd2b00559685045a376569e28db2089623e9f633e05c112b92b8c8b30187611938781367ef040662184a53795b9eaca3cf22217d307f348b5f9c4bf254738c683ac0e205dce9209e3db8aee5daa2f8b287060ee257adec8c3145e023df609e19210d8aee6427217a27e5b2dd22ef7c03d61e2d1bdb12cd3a7e12744412752c24b957e17ba34e71b0af30d8d8504c8373409aeb6c26b34241b5cc4c67c016807294155f7d662235ab7060cc27b19908489e6a9fe03531c42f1476ad1d629888f38d42f70fd13237e8fc27017d16fb5d9c1434a69100dd0b3b3f23955b4dbf9e356ab6813ea0d2cb9873654b3db59ec3f2d06148cf0a0dcef67e849787a8c4a279328f8a40054e5c15ece9150b75ca1974b0c7a97be35f1b9442df76ad47dae6163e9bb66cb9dbbf421c67a356bd3644e9bae75da7456a23add38a479838d3f7181360e9d7f2395c70cf8413bbf9cd71b7079a0df9939c2a25b60f49502d24a83b90926d5e2605c710ef101051bf25c0eb3d9862a764395ef7743150bfcbd36e45b379eacdf15e4d5be1b19bb91f1c0a0426e50c5d1a7b249488095b5806944670671b5801f95ea08916ac414b0f410bf84ac37ece87d5a46fd3e0ecd32512aaba6fb962a586df6062acdde189905dfaa1da8f876fe88f90008f4a7c2fa5370b10d6d5bc787476945ec45e2bd53a48506cf1fc00781198b47ad573124df8c758cf27eee174990abf77b60dd03acf707b4462c2800c18fb4b01a83e46f2505bc3ad0c572bb972eb49211c45044cc454bf8955612917d3545cef8bdf450c6be16d7294b8c417349f250cb9452d549cf3f2a50f1b7491491b48b4aef837016e9042232239496472632457a85aa5ce061bc68aabad29998e6f28897f39d9fd3546e1dc9e510e46d341d04d201209f6a6de44475849a8232c1e69cbd0ab84a72a23e39511f9d28d6984294668d358c754e34cc154e9200130bcd7e5463cdf635ec40b1408147573771051d26f43b407713da0a4fa21d433412742463884686147182081912e14126740243f0be07b8afe880f591875af61dc0fbf8aecc181417d78121e54186f84ce900f615596a17a9bc8665fd885e21b5471c430a546782ad159054a047111301d711ba5290e0d289e6f32c2e0c6d272d26a58f6f20114108c6969513ff28d045e0a6ee95ac7a3181e698c04322bbb000ebe089d51ccf7ec02cae556839a5125ceab725ccc41b8c1eb27325ebbf1d2b4126c214f330aa6042e0701dea3f49943f0f1cf3d7309cc0e31daad6e9d45b4b5082428827d83fa3106aacf6790e8fc6b6df81f042935540394043048285123182815f6f3795d6e6fbc2bd54bd5c0842142af21602aca805a6385f8d580fc0be410c235138026667113b50ecf8c446529191a31b09bd786223ac3ce5a449a2e86de1f2a144d9dccae4dd424269cba05b596cb76455d10e4a206c4fda1e24d69c1b1d98328f6244841b2d820fab48ac9980b5a29de69094a2a87249db30092f25810c9731ac2a7058e5715835c2a5529880853360bb1738bb15f6db3d5c6fc247a7744181ecde56b67b2267f7a4832753eb3b352b58bbe70faa996682cb2a157769435b6c20b8958f78a98e1b5a6d3465568c32aea48c6f6c05f2b392e241debfca540f236f6db5633076f3aa1ebb6a77e8cdb7a5263854c53a35e190ce6afa59eaa1f14d9fd59479ab49062eb39a78e0d64b3d3cb49ae4fc514035959dd96a52d6e0df171f89de2a29501b3c2b7e3e225b1b9482e9b9c9395668ff943bb6dbe4dad90d83298ce2f3908bbb76b6113486221777edecd941c743416f1f0aba3214f4cea1a0cd50d0634341d78682de3d14f4f850d07b86829e1c0afadaa1a0d75d3bdb0cfc22af9d6da6e11b5d3b7bd70f4b1114d217b260e410dee1f91e454cf6a0efa94d8ce986cbf10796e3e3727c36a653942ab9ab2e695ce51b765914925d34c3eb0584b7ff928b8f9755426b7a7d3e43c6733c8c74507e47ece5962245ae8ff1e5165ea2e2db2545bcdc1298882eb70474b9a5880904647926c0cb2d7c210853dfbecb2d23a688841c71b06ef923682647705f38edbacb2dca5d6e51ee8a1e044ff0307845af68f3489c28404af07c9cb172a09dbfac66893670654ddb2b6b156ef195352a920082902b24ff0234297089c4e76b6472af7e0357476ecd7c5adc8a27b32b589fd6da73272a3f3492d02702c47bdff23eccf3be90e77dc8bc2fe4781f5e0cef7d1322ef7d07eb16ec5305c1f23ebc28de871bf03ecc78ef33ef79bee1796fafafeecb38f984d4bafff09e534dcdd11ac479938b0ff231b8a03b0bfc9501e3e301bb6f0fd8dd3d02bea768c3d79a1a4f82072921d81cc65d3c0cdcc1bca2948e025ce884e8f63b0fbbe8960da5403b4ba01eb808ac54b8dc2ea6dc6e2b9dcef3f707becb056f3db039fe36005d3ee0648f32217d1f5e4c03f18245828cdd06c94bd8e13a777b9fd89abb4c22d65d60f1b0fca250a865cea24b9b0006f66e2e85f04cde808894c3196e8cd31f080239d9f031aabc7dd4dd5708f05e09c394f2a488be2ca968a172fbe77a8491d7a898f33fdeb587bbf636dfb5de68d79a7de0fa5debfe5dc72e9ff3b890e330ea8d31ca01a76cf71cbf617480c997b140502ac5a251c55b1e9bf69f54d2e5345420a66b1f69d24a6cea586b5da3c414b4ae1463a93cb183aaf0026557f4c4822f94b89b313555a3e190eeca9328e7277624545cc7537d41b34677ebde45eaf55288eaf5024aa193c390e550daa2d0356a9ccf1c9e71fa2d1733fd96cda777da1ea26df0d6ab7c083a0d2aff914732950f3188f4fb32262fbbc6bf5e5906c2319a3844331172323c6826662133ecc90a05665846419385c7315e2e865bbf5fc59e6c60b3140272ba9a5669ce17649207e40b300b0878b53f30de04951e40652f9b412614ffca68f4bfebcd122b0464fb3015289246457ab06a2b07fa05b25376053eae007e9d48821d547fa7f204393113eca0928e9dcbf8376f38d706a78f39abace8ff51b21f6c69680e48d5807578a1ee43f6c8dbd0972e385ca1faecf6dc972f54894fbdbc768fb7aea2b071b6c3570a37b2ad5e5c1fed37d574644bb78eb9fa63cfd404dd9427ab78880f410416a73caa03ba2a72a545afd97de78b531e579d5455d813ef880b3d940cd1bd443a5f93947aec7575ba982f43e2310af495285779efa336e2a3e393dfe4dabcb7cecdbd90b5797bc01da2455f5f9b3f6a0fb7fb6af398b54c2e606dde52d547aa6a7b993f09085faee487afc19c0d50d5d65835acace082a1ac6ceee7cae68e7546c733a37d22136c94a20648df3dc4c675592a9e9022c67e9b1abdcf97a5fe92fafaa2fae462afa83ece4575c545750ae928fa5759415a6505699515a41517a4b9d55f729fdca0e49e2bb51367a8d4fec7bff399b15bca32bd173e7395761ca1d3dffeccbd97e0b93df2477636acb34b94e6c9855e6d1df8686bebc8d15e6dfdfbda1452c6b526fb2aefd90568577da76fd76c548ca6afa8b8aabca4aa3c19f25e551e0f6a6c191e9016f135c95da9ef4487dcb29f9de9bccb4a1e558f4b5c568fe87e2d0c7a73eb1552bc0adc367a0a40ce0568b73a8e3cdd22eded5a5a964d3e73c74b9e3b5e22d9b59573c5674b62500324ef07b1dbcbbb51ee2b132c9deea2c33ff2d726b43b6e1dce5684eb6d85665ba1d9568483b602ed02dfffe0cbccad9e3f090f0eaa60c85ff419f05ae1a05bb65ffa8047cbb35a8b4ae68364e2cbeac2dad571fe4a079e89c19ef82c862e36715a29b22be771efb9c0076bfc5ca2db2530517c1ca93cce36e046baafb34b5888cd66100333888119e8f9b945764aca2ea153f648c9a2b332db43e7de3b74eed9a173cfbbf179379fcdf0dd7dc03db6578d1985da6baf6a89e85f3d3e80b820720e1d355a91d9e5e72d4a487bb2c65fc822552850c9220b80d5c10d1cbbef2e650c446eb6f6d02722d951ef648bae24af131172bd443c998908c519fd64a7ae7e41a1ae7e59b1d772acb8287628b91066f7f3b55d40b52b1ff36e84c75b87878d277ecd3151f1dce8b3a31949047d75d589d8581ff5f25296a39e5a4f3db59e7a3d7173dfff1888832e5031e7bdf82d99dc25672475858411bf254bc24cd70459e26a78560e215fa2e7f972076267ee2877eebb724b59d9225ef10632c1f8d5191403205e9be319f465f8a72002f08614a3f3371c021860bf6501e61fef82f8643d1118bfb2435f6fa3ab6d1eea8257a65b02ec8d383486d4fb0445c648399c09e370776c2c266cbceee2677817bfdc1eed66c62eafb719e19e13fc7c9b46f211329333e6909936bcdd391f63d34d886d7f121cd3d77d4d7f61233a7dacde5c68cc9aceb2a92f2c2ccfd43b0db3523fde58156b4b8d532b8d990ebc6cb4dbcb6dd35c32c79aa71ab3d3474f771aab66667969b5d35e9be92cb74567ae6196977818ffb91b33535f5a5aee98a30d682de00cb3cd36605b382ddc4ffad68745f4a4679ff0cfe300be467dd1d43b9dc6e24a8757f5a6769396b4da31384b6369561485fd333c801356da31d95fe3d967c44a7bb9b33cb3bc60dc98e6aac185f4fe620fff012c05fff4b39b57e05a7df817c0bfe5a32dd80e0e58650018deae0331a6b1cd7302c516d7163acde9e6d26ce39460fae0df046a2e1dcfc60b4ba91978013332de5584edd48f2e40c7315387f7738d3692bcd3868dac9f7c7179b679ecf426f3da09ec988b9a80ffea50db717166aebe741ca8d16e2ed6dba7cd7ce3b479d35c63c9a2c4ddd4972ce24d098afbeea7e7f1464788106859807f23f0af08ff22817f8a4588e6d2c9fa4273d69cacb79bf525dc136ee5d90825d8dac8fb6a02b8fe0f216a74d100d00700008301010100203d33cead0d8cb33323616dbe9a5ffbc9ba05f2b727d2be15c3832fa53e9260492fc88e9db27ca1cb7eb80ea3dcb514f23d4253ec80d5ed34b02b43a922ac95730100e70778da8d56bd8f1b45141f7f9cedb393d3e5201c97822288265220e704eb74d551d05050f0511d6119ef3c7b47de9dddccccda67a891083448744142114290e2aa4b135d2822b7202402698002e840e27fe0cdec7a77bdc7999b623fde7bf366de7bbff79b69fed179b7463edafdfe21c151310ff2f7b5b7cdeb817b345b10dcfba7dbfd6c632eb9bdb106a1e2e1ee2eedf397b65fec5636fb7ee88e1cc587828ba14363ed8592ebe9e531959c0aed9ca277c6d7b65ae8c4f1a8f24875259c0890754103a81b49c7f5c01da938e8bedc6b5157f331d5402a6b03a03a96e0303e04a58b56ab996b525fd59e04e5853e6bc45ce8ebddfa08a6ea1c3e9c09f0a1a7f76fa253378c85565b11c8802b0c4a383e8cc1cf4c5626946b75de3c33d9a5d3c321d5332c7bd1ce773dca85135189e16a908a5c782aa00769aa046827567408d649efc6254de5107459eb44ae4e97d93293b5a442994c611c8b2eae779feb538513402eb55acf7dfb00133a4de5cfbba1d070a09d81049379651357d8898883b39a3210a9692162378a1736b21871a65d1671d9c55680095e66f06cd983cf07a07990a58cc100a4048646070e1c445c526b37e1828593d4ea62d90b033fcbdb3346c985cf0538a95af1f7e70b6c9ed43288b467d5db3d9b9e1c5e4555c7a5c205df2e45aa6bc9df1c8deb653837ccfe392bb64a1ba722ee8c39a936d346b0bdd7ce6727ff397649b5863fed28eefbdc75f0b391c8d34db5700723ebb1bee0b1ee860c922f3d8d92af8e845b319710c07c5981704b26e174576293872919648f8421f22e6f5856805cd00c512f43897da84030043b674dbbb9ee4e0b25da5472a53fd5a04e24090908dda56b9693b0790a43906ac1f264de17d2b311c990c52e6e2aa7a9eaf94c98459987731ab19ec3e4cd09912d65c4a6b13415a9d407320cacff86028dac5b2a7b0d454966da46eff30089af54c855242bc7daac585a6a9ba64e624c05a6c58a8226fa32d52f396a8c0383841593989dd571304602c4ac25ff162ec956b08ada52a4229546f2f1dfec69d689241f97826a72e51871e2b8658d4286ce5a0a93c4621f9e3e5994fd9bed586450aefd2f94db71c468da4af5a5ad644298e3bd6eecf352770a470ca9b6ec9f0237258a4520ade3417ce5733c94f353917c7bfbcaab1f7efdca022f90bdef7eb977f8e56bc55ec7717554fbe693bc57c9de17772eb307778a0d88e3f7c71f3cf92aeba74fdfeafd0aecf078117938ee4270789ca16c7e7d98438c901f5e3ff68e664548e1d87be1e3a359060d421e3d7ee7cdfbb342b171bcf770fffe2c2b2b8e9d1f519097d004f7e8af3f7f2ed6ca06ecbff1a458117393b94b7ffa6dbbc67b3708c9ef1b78eb39c305a5b2ecb427ff024faa597d0001 +DMLOG ACCEPTED_BLOCK 4 04000000040000000300000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000300000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7192d5b1b639d6ae94fcdd0536b224644931573d1ccb2a0c548613cd1feea18888b5a5902476311cae3e60a34f4b68b4336275d05d6835128c04ba783367af61f050300000000000000010000000000ea305504000000010000000000ea305503000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add801000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e5033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc002011cfaa913847cc0153220aaca619114879a97d55942af073d83a71fd044ede7257cda33f044c154d10a137e48e9862e00bf114268cc46b3eef3a622c7fd6c3a20000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001150ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fccad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001033b3d4b0000000000ea3055000000000003ffc4d414883accbbe91f60218a47d4c1e1914fd6ebcc2051150df7196b5bdb9f6b98a1a4629cfddea5210c8afcc2c3b5364a9e9906716f0e72dba9e90d2ddd212cdd265a1ec5551fc1187ed73259766adad832e3a0e143676db9055d00000000000100008105141a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b7241ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea994a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0fe0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff52668dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a297428ad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c438ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a4052652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c2299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b4476707c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead450715443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b4bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb406bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc35c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b98c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fcc002011cfaa913847cc0153220aaca619114879a97d55942af073d83a71fd044ede7257cda33f044c154d10a137e48e9862e00bf114268cc46b3eef3a622c7fd6c3a20200d0070000dc060101001f00e74c5607ebe92350dc791bb2cb65c8ceb52fe6623104137f710805b93a84e23a3530fea5cea3743b77736669d4962f0be8dbe1bede210eb1c2460924b505a60100af3578daed3c0b8c5c5775f7f33eb3f366ece7609261ed36771e4b3aa64ed90467bd3569e3b725fe902f69a0f4c77abc3bf6ceecd7b3b3c6aea8c734566a3e95684b4b12aa1650da90d05029204441544e4a24a0544d2141a42a2dad2a15416953552a1451d2f3b9f7cd9bd9dde03049402a9b78e7befbee39f7def33fe7ded9f09fa2376a717edfe73e21e047e22ff1b5f1d7c1effd2f7bdb438fe43bc407be71f5d57f7577aeeb2fe0a1beba883df22ef99223421c51ddae38a2bbf8db3b033fb27b44c83347bcee9933d0e577f107fa347fa8ecf719fb4e1c09108cfae519c077c66102b46768a0841ed925c4080b2f003b4dcba3ba04c2c814f4a8a7fc31dd583a19cd1e9d3ed65c9a9d6e4eec111a7b4a8de5d5e6f2747d75b5d1ee08895df1cc5abbdd58ea4cb71b338de6c9465b78d8edd78f2ec31081ed328f9f5e9dab5f7dcd845084bbd77715f7e4465d73d5d5dc17dbbe7673a5b1387bd5c4387707794c23d3b09eb9854ef395c2c767af8732c8e31a194012c1829761bdd3f38dd322c01eb3dae84c1f5d589e999f99ab3797a657eaedfa62a3d368af427366be31cb3b0e161b8b332ba7454830c7bf174c01875d8aa857dacb2bcbab8d596cccaecdc0183142547524ec34171b4cbeed88b63ed30182e64613aac24abbb9d4599d5ee0d55ce24894db4d91b002f7563bcbed06b12fa2ae76e3c45a137aea6b9d3951c2ae2dbcb0e6c9e642e338acb68c9d2fc2ce76637579ad3dd3985e682e363bab620bbe79c9c6fb986e9c125b0972a5dda065d73b8de9638d7a67addd1031518d97cd0fdb9babeeedb41b3e2bb631cbe17979697ab6dea94faf367fad212ea16ec03b3b9d7bc7c4d89617c8e999e5d9867811f61761f34842dc3af1a90c1d6b2bb3b82cecdbdea3e41cac5dea03d78b176f8bc5b6388e4b7141c5971654e132296359e19f82b41fb252c04f5180a674ff54411614fc143c5faec872d9d752c8e052dd95e9d90b22ea8af49f1fcd3ec211e9d75756164e8b978d5c22452aa3d2eb5eff0bbff84bbffcab6f9c9e6d1c2b7ef0edf27a4fc4b5e8cb5a18115f198f1961e46bbdfd5367cffecfe3f79fbbfbefefe91a05cfd81dbfca87ee07bff85bbff79efb5fd7ebbdd6f57ef06f3f2b7add3f83dd67bffad0372e7ce1ed391c3f6b477fece3ff797baff73ae8fdd69f3cfef90fbcef0b0fe770ec271c671fffd4fb9f9ceaf5a6dc7bf69b77e57b5fcdbd1ffaf63f7ceddedc7cd773f747bff9c5fce003d8fbb1ffbef7ddf7e47b0fd2d80bbffbedbeb187a8f7f7fffaeb8fe77b6f64bc7ff7a7eff9e2c773d3dd4cdd8f3df4e14fdc7d75aff7167fea9df73ff9e497df7177dfe05b7d23782b173e7ed713e2366f7f4acf4f7ee1c3dff88dff10b189067ffcdc70c7a7be3d0382b7f42348457c55d496baab60d2b248c556e84a454dbd039ed3f864225b899a8027ee3db73fd146b4d2adad74e5442226a00300551a778cb801c1a12d5b38de4868546504afe57e91760fe2dbf49d17442c23a32325a20929bb2f8539e6137833a14a000c33946a4af4d09fdd8fbd384d2aae1388377aa5545d589a34624755aafd1af0c75724a22c5351e535a689babe2c8dda2644494491115180e2fb13910f3a2fecef222e56ecd5e7d3e8665ec857c47c22c78070b0f42f09d844819a31b4bcac85af45fc8a517a34b286af60c5f3f116e8f98a688d89e8fd05582192b30618e09797a8f9347c0defff61d83f7556556414c014e2ada38676eea505a2b587bdadaa7628005a6f0cad532f07ed65d0a5a1a0e3a1a0b70f055d190a7ae750d06628e8b1a1a06b4341ef1e0a7a7c28e83d43414f0e057ded50d017443fb8dc0c5ce5c05506fe0880cbef0d2e07c0115844df965a76d519b23be3f38926b38373c5adb83025aa5e1a57d1a02968fb60e2f08551ad6aa0d0de02cec36561fca9c29dc633c155429c4bbca9c9f3e7aa3ebcebc2ba8c07efaa5e89ed6f2a0fd0daee67eb0b907b35982607bb570b9c0eed7dab2a70769c3522539ea8d480e9663431a0e94daf011ee7d39df4542b1e8135165abb34401a8d1f1e4ee4edc5c881e603ab0fa206f6114cffbb212c817cc0c3ed3f2578ff1a1410fd00b4a6c02e57e0a3bb57c7308d007489874bd6849068e0c116d1bbddf36f1ff9f7abc00508f42287687d0011bf32017a8f1bcd1bbff008bb1d03bc1bc7f7b496780fd3c78bd56b69d8dbfe12878160c4bb12818b888126b556e2631bf6012b4c02d7aeb492d0b68d46b4c0427c42cc46814f480af8e199c27c3c0e84c27e0082bde0a8809f63f71c22d1262db65d7a9c774e636a203373f661421de109043b0e3ba4d09e50b3d00407445c8caf19653c853c8d2c212dd6f8d2c49f507b88943032be1d593a7506c82adf0cbf7efdf53b600d48334193665c40fa01e06ee282aea99d89c20f730bc02b7c13c307732b25506598ab204f15d8c0ce1272029a76bdb41d0d362c9e8810d191aa7090e2fa323aee97473c5325f1af2f8bdebc205707510daa02506a8c57e65ac876501b4321050a83421c0a70000b044a3261aae2272e7627e187099f22df7d2ed0234e2f311e505558f618cf297005a0bce06690bb3e29034ceb83f8d7303038004107a804ae02175652107bc0f3015c2374e2c2029238fe0f5407561957133fedb2edf82f1453248f9fbec53b5cc6467c45354c65b580bd405d8e8ce693700cc65741a724488e1f5747596803165a2ba301127edc04406bdb0102ec5a356e295c7f48a15bfae4a7484b0213b270851886788a77985ede3708e5bf3a0278c06414817c604c8d971a0003db118139f149a1ab2a657352222346a35ad5326ddf673352422b16993259b188ac5809de8115f34d84562c622df59d15fbe8a3b402654a2864cac1b215f331186d91dd8c705ae0005a312fb362beb362767ab45a8002a7ec1932524b58066a5035c2b922a41a4f199922be30d853446878a8f10309b5c9a97911ed3675c53dcd97a076207dc18432f8817a05e8d16ec19b9d4ed676263e591c101b542d1f5fc6f01165aa65e02940d542f9ca546b84e6b3c4d620aca05780b1807a1042104cca4aec6114d8efb30e50fc6a82e82ea5159867d20203d6b90a16628c2c3fda54c16cf824194bb53f56641ad8827e9d3a8d643fe0b11da45f011bc3008d21c63bc0978c4a187bc173dc7b06427a407b7ac016893585a60a594713f08c7fc8f2a8d35b5be446d0bcd52878f7d02ca3ddb141b647bc46ff0beb420b09bbd9338512508b13c22aac191460067d34837e66064180d03e7c5ef7fc3650064c03b978da49a2af1597714c4f8fde94397fadd0680da76ad052d41a8796a4d624b4105cd3b81761eb3eb0058593fbc4a5a4eb31b45e4cad0ab4b623100cd82742eac3714136cecfc679b8049e7ff24e9cfa4ece0acf5e785adc710e3a2ab6e32bd7dd4161023d3d75f91de7f065e13c3e7e6b2bbeaa60fb3b2101d5a0fd5d7d072dfbdcb973ac79304dfc3c4f53210221d1b6510b097909b5907c715f9a25e7d3cbd9909e7f240bc2501ac126985c1066480814711462b17bb4f4bbd624e37bfc05d49b4f2b8bc00e301e41fac1271e7802b5307d001bd5d08d0521a3615efaf8034fbc1c0c246837d89b4e1282590e0eef48425c0e587041b11858d4ca42bc0b432349de005d00ca287a8dca4202f99f44f514a8e9b06a927bcc42031e84e02d8af1c0f80636b7e4e586ec7c0a2d703455a931270737e4e12c1034f12c921502e5135eaf406c97e91b4697d04d53e3f31cc590e04743e391d3a4292d49439a12760401ae8877c3db90a33d1fd54ee06a3d8c86d80103063018b0a21057142224382de79e259a1f89e607b687335140869d1e74468f29ed394b1493bea5b821f2ee3015b8308525075e359283d3f1c49f4ffdb507ab01791d09713ef8c4f03cfac7db70378a286179eebb052a6b20d024600a4d569588fb8c98d237134c98760f9495454dda586ac5af1d251348b82078f42d35897ebea526901136e5a39c808cc4b78988431cf4ece0e96f2a534c68c2f9f8e72c20455026bc85de802547798e38f8f2f8031780d8914aa0a7f1cf8f925f040bf6675aa105ebd92f34def165cfb11913991913991913793326d88c89cc8c89cc8c89ff7f660cfcd18ef4939039ee045efd74fa096ab1818afea0dfe570854a585e29e4153e32afb4e595b453286a31afa49d8c324dcb2b68dd07c68b7925d10513afb0c5bc92c84c0f79857dcc2b37cecfc6792eb7d048443d4844dd4744dd4f449d23a2ce11516744d43d5ed134f1f33c4d8508c4bcc216f30a5bcc2b8856e29752cc02dcb9ef4701c10f5b40a0e21fa320e04b0f739ec08cfa73293de7457a491d84af3f9e78655b732860c5859c00d958ae33a467bdc3e48eaea82acec23c978501127a8e2f1fb5082c300c819c4a46bd7c09f312ced83901436f4bb1ac979e3a91160ee6732b9d8d6593fd6aa961e5b86c5eae4b822f72691106ef3f42b20192cf289689f13e9960894051789632600b4c63fc81b91df4b7b0ca52b3352dc295cfb631daab6132565363582fa4ba88e33e0909961bc7284a51079f09ee3284930e4e3e039c05b8740080169e52e899c932e59185563c35ca35974242e514da5f89ab2ab6a8f7b4b4153d5bfa84dc5b63d4abe97c8862e5c3b48c3b1eedab8f5e292810e22553e088a1d2d3e20410ea697922519d07cf216bd2b00559685045a376569e28db2089623e9f633e05c112b92b8c8b30187611938781367ef040662184a53795b9eaca3cf22217d307f348b5f9c4bf254738c683ac0e205dce9209e3db8aee5daa2f8b287060ee257adec8c3145e023df609e19210d8aee6427217a27e5b2dd22ef7c03d61e2d1bdb12cd3a7e12744412752c24b957e17ba34e71b0af30d8d8504c8373409aeb6c26b34241b5cc4c67c016807294155f7d662235ab7060cc27b19908489e6a9fe03531c42f1476ad1d629888f38d42f70fd13237e8fc27017d16fb5d9c1434a69100dd0b3b3f23955b4dbf9e356ab6813ea0d2cb9873654b3db59ec3f2d06148cf0a0dcef67e849787a8c4a279328f8a40054e5c15ece9150b75ca1974b0c7a97be35f1b9442df76ad47dae6163e9bb66cb9dbbf421c67a356bd3644e9bae75da7456a23add38a479838d3f7181360e9d7f2395c70cf8413bbf9cd71b7079a0df9939c2a25b60f49502d24a83b90926d5e2605c710ef101051bf25c0eb3d9862a764395ef7743150bfcbd36e45b379eacdf15e4d5be1b19bb91f1c0a0426e50c5d1a7b249488095b5806944670671b5801f95ea08916ac414b0f410bf84ac37ece87d5a46fd3e0ecd32512aaba6fb962a586df6062acdde189905dfaa1da8f876fe88f90008f4a7c2fa5370b10d6d5bc787476945ec45e2bd53a48506cf1fc00781198b47ad573124df8c758cf27eee174990abf77b60dd03acf707b4462c2800c18fb4b01a83e46f2505bc3ad0c572bb972eb49211c45044cc454bf8955612917d3545cef8bdf450c6be16d7294b8c417349f250cb9452d549cf3f2a50f1b7491491b48b4aef837016e9042232239496472632457a85aa5ce061bc68aabad29998e6f28897f39d9fd3546e1dc9e510e46d341d04d201209f6a6de44475849a8232c1e69cbd0ab84a72a23e39511f9d28d6984294668d358c754e34cc154e9200130bcd7e5463cdf635ec40b1408147573771051d26f43b407713da0a4fa21d433412742463884686147182081912e14126740243f0be07b8afe880f591875af61dc0fbf8aecc181417d78121e54186f84ce900f615596a17a9bc8665fd885e21b5471c430a546782ad159054a047111301d711ba5290e0d289e6f32c2e0c6d272d26a58f6f20114108c6969513ff28d045e0a6ee95ac7a3181e698c04322bbb000ebe089d51ccf7ec02cae556839a5125ceab725ccc41b8c1eb27325ebbf1d2b4126c214f330aa6042e0701dea3f49943f0f1cf3d7309cc0e31daad6e9d45b4b5082428827d83fa3106aacf6790e8fc6b6df81f042935540394043048285123182815f6f3795d6e6fbc2bd54bd5c0842142af21602aca805a6385f8d580fc0be410c235138026667113b50ecf8c446529191a31b09bd786223ac3ce5a449a2e86de1f2a144d9dccae4dd424269cba05b596cb76455d10e4a206c4fda1e24d69c1b1d98328f6244841b2d820fab48ac9980b5a29de69094a2a87249db30092f25810c9731ac2a7058e5715835c2a5529880853360bb1738bb15f6db3d5c6fc247a7744181ecde56b67b2267f7a4832753eb3b352b58bbe70faa996682cb2a157769435b6c20b8958f78a98e1b5a6d3465568c32aea48c6f6c05f2b392e241debfca540f236f6db5633076f3aa1ebb6a77e8cdb7a5263854c53a35e190ce6afa59eaa1f14d9fd59479ab49062eb39a78e0d64b3d3cb49ae4fc514035959dd96a52d6e0df171f89de2a29501b3c2b7e3e225b1b9482e9b9c9395668ff943bb6dbe4dad90d83298ce2f3908bbb76b6113486221777edecd941c743416f1f0aba3214f4cea1a0cd50d0634341d78682de3d14f4f850d07b86829e1c0afadaa1a0d75d3bdb0cfc22af9d6da6e11b5d3b7bd70f4b1114d217b260e410dee1f91e454cf6a0efa94d8ce986cbf10796e3e3727c36a653942ab9ab2e695ce51b765914925d34c3eb0584b7ff928b8f9755426b7a7d3e43c6733c8c74507e47ece5962245ae8ff1e5165ea2e2db2545bcdc1298882eb70474b9a5880904647926c0cb2d7c210853dfbecb2d23a688841c71b06ef923682647705f38edbacb2dca5d6e51ee8a1e044ff0307845af68f3489c28404af07c9cb172a09dbfac66893670654ddb2b6b156ef195352a920082902b24ff0234297089c4e76b6472af7e0357476ecd7c5adc8a27b32b589fd6da73272a3f3492d02702c47bdff23eccf3be90e77dc8bc2fe4781f5e0cef7d1322ef7d07eb16ec5305c1f23ebc28de871bf03ecc78ef33ef79bee1796fafafeecb38f984d4bafff09e534dcdd11ac479938b0ff231b8a03b0bfc9501e3e301bb6f0fd8dd3d02bea768c3d79a1a4f82072921d81cc65d3c0cdcc1bca2948e025ce884e8f63b0fbbe8960da5403b4ba01eb808ac54b8dc2ea6dc6e2b9dcef3f707becb056f3db039fe36005d3ee0648f32217d1f5e4c03f18245828cdd06c94bd8e13a777b9fd89abb4c22d65d60f1b0fca250a865cea24b9b0006f66e2e85f04cde808894c3196e8cd31f080239d9f031aabc7dd4dd5708f05e09c394f2a488be2ca968a172fbe77a8491d7a898f33fdeb587bbf636dfb5de68d79a7de0fa5debfe5dc72e9ff3b890e330ea8d31ca01a76cf71cbf617480c997b140502ac5a251c55b1e9bf69f54d2e5345420a66b1f69d24a6cea586b5da3c414b4ae1463a93cb183aaf0026557f4c4822f94b89b313555a3e190eeca9328e7277624545cc7537d41b34677ebde45eaf55288eaf5024aa193c390e550daa2d0356a9ccf1c9e71fa2d1733fd96cda777da1ea26df0d6ab7c083a0d2aff914732950f3188f4fb32262fbbc6bf5e5906c2319a3844331172323c6826662133ecc90a05665846419385c7315e2e865bbf5fc59e6c60b3140272ba9a5669ce17649207e40b300b0878b53f30de04951e40652f9b412614ffca68f4bfebcd122b0464fb3015289246457ab06a2b07fa05b25376053eae007e9d48821d547fa7f204393113eca0928e9dcbf8376f38d706a78f39abace8ff51b21f6c69680e48d5807578a1ee43f6c8dbd0972e385ca1faecf6dc972f54894fbdbc768fb7aea2b071b6c3570a37b2ad5e5c1fed37d574644bb78eb9fa63cfd404dd9427ab78880f410416a73caa03ba2a72a545afd97de78b531e579d5455d813ef880b3d940cd1bd443a5f93947aec7575ba982f43e2310af495285779efa336e2a3e393dfe4dabcb7cecdbd90b5797bc01da2455f5f9b3f6a0fb7fb6af398b54c2e606dde52d547aa6a7b993f09085faee487afc19c0d50d5d65835acace082a1ac6ceee7cae68e7546c733a37d22136c94a20648df3dc4c675592a9e9022c67e9b1abdcf97a5fe92fafaa2fae462afa83ece4575c545750ae928fa5759415a6505699515a41517a4b9d55f729fdca0e49e2bb51367a8d4fec7bff399b15bca32bd173e7395761ca1d3dffeccbd97e0b93df2477636acb34b94e6c9855e6d1df8686bebc8d15e6dfdfbda1452c6b526fb2aefd90568577da76fd76c548ca6afa8b8aabca4aa3c19f25e551e0f6a6c191e9016f135c95da9ef4487dcb29f9de9bccb4a1e558f4b5c568fe87e2d0c7a73eb1552bc0adc367a0a40ce0568b73a8e3cdd22eded5a5a964d3e73c74b9e3b5e22d9b59573c5674b62500324ef07b1dbcbbb51ee2b132c9deea2c33ff2d726b43b6e1dce5684eb6d85665ba1d9568483b602ed02dfffe0cbccad9e3f090f0eaa60c85ff419f05ae1a05bb65ffa8047cbb35a8b4ae68364e2cbeac2dad571fe4a079e89c19ef82c862e36715a29b22be771efb9c0076bfc5ca2db2530517c1ca93cce36e046baafb34b5888cd66100333888119e8f9b945764aca2ea153f648c9a2b332db43e7de3b74eed9a173cfbbf179379fcdf0dd7dc03db6578d1985da6baf6a89e85f3d3e80b820720e1d355a91d9e5e72d4a487bb2c65fc822552850c9220b80d5c10d1cbbef2e650c446eb6f6d02722d951ef648bae24af131172bd443c998908c519fd64a7ae7e41a1ae7e59b1d772acb8287628b91066f7f3b55d40b52b1ff36e84c75b87878d277ecd3151f1dce8b3a31949047d75d589d8581ff5f25296a39e5a4f3db59e7a3d7173dfff1888832e5031e7bdf82d99dc25672475858411bf254bc24cd70459e26a78560e215fa2e7f972076267ee2877eebb724b59d9225ef10632c1f8d5191403205e9be319f465f8a72002f08614a3f3371c021860bf6501e61fef82f8643d1118bfb2435f6fa3ab6d1eea8257a65b02ec8d383486d4fb0445c648399c09e370776c2c266cbceee2677817bfdc1eed66c62eafb719e19e13fc7c9b46f211329333e6909936bcdd391f63d34d886d7f121cd3d77d4d7f61233a7dacde5c68cc9aceb2a92f2c2ccfd43b0db3523fde58156b4b8d532b8d990ebc6cb4dbcb6dd35c32c79aa71ab3d3474f771aab66667969b5d35e9be92cb74567ae6196977818ffb91b33535f5a5aee98a30d682de00cb3cd36605b382ddc4ffad68745f4a4679ff0cfe300be467dd1d43b9dc6e24a8757f5a6769396b4da31384b6369561485fd333c801356da31d95fe3d967c44a7bb9b33cb3bc60dc98e6aac185f4fe620fff012c05fff4b39b57e05a7df817c0bfe5a32dd80e0e58650018deae0331a6b1cd7302c516d7163acde9e6d26ce39460fae0df046a2e1dcfc60b4ba91978013332de5584edd48f2e40c7315387f7738d3692bcd3868dac9f7c7179b679ecf426f3da09ec988b9a80ffea50db717166aebe741ca8d16e2ed6dba7cd7ce3b479d35c63c9a2c4ddd4972ce24d098afbeea7e7f1464788106859807f23f0af08ff22817f8a4588e6d2c9fa4273d69cacb79bf525dc136ee5d90825d8dac8fb6a02b8fe0f216a74d100d00700008301010100203d33cead0d8cb33323616dbe9a5ffbc9ba05f2b727d2be15c3832fa53e9260492fc88e9db27ca1cb7eb80ea3dcb514f23d4253ec80d5ed34b02b43a922ac95730100e70778da8d56bd8f1b45141f7f9cedb393d3e5201c97822288265220e704eb74d551d05050f0511d6119ef3c7b47de9dddccccda67a891083448744142114290e2aa4b135d2822b7202402698002e840e27fe0cdec7a77bdc7999b623fde7bf366de7bbff79b69fed179b7463edafdfe21c151310ff2f7b5b7cdeb817b345b10dcfba7dbfd6c632eb9bdb106a1e2e1ee2eedf397b65fec5636fb7ee88e1cc587828ba14363ed8592ebe9e531959c0aed9ca277c6d7b65ae8c4f1a8f24875259c0890754103a81b49c7f5c01da938e8bedc6b5157f331d5402a6b03a03a96e0303e04a58b56ab996b525fd59e04e5853e6bc45ce8ebddfa08a6ea1c3e9c09f0a1a7f76fa253378c85565b11c8802b0c4a383e8cc1cf4c5626946b75de3c33d9a5d3c321d5332c7bd1ce773dca85135189e16a908a5c782aa00769aa046827567408d649efc6254de5107459eb44ae4e97d93293b5a442994c611c8b2eae779feb538513402eb55acf7dfb00133a4de5cfbba1d070a09d81049379651357d8898883b39a3210a9692162378a1736b21871a65d1671d9c55680095e66f06cd983cf07a07990a58cc100a4048646070e1c445c526b37e1828593d4ea62d90b033fcbdb3346c985cf0538a95af1f7e70b6c9ed43288b467d5db3d9b9e1c5e4555c7a5c205df2e45aa6bc9df1c8deb653837ccfe392bb64a1ba722ee8c39a936d346b0bdd7ce6727ff397649b5863fed28eefbdc75f0b391c8d34db5700723ebb1bee0b1ee860c922f3d8d92af8e845b319710c07c5981704b26e174576293872919648f8421f22e6f5856805cd00c512f43897da84030043b674dbbb9ee4e0b25da5472a53fd5a04e24090908dda56b9693b0790a43906ac1f264de17d2b311c990c52e6e2aa7a9eaf94c98459987731ab19ec3e4cd09912d65c4a6b13415a9d407320cacff86028dac5b2a7b0d454966da46eff30089af54c855242bc7daac585a6a9ba64e624c05a6c58a8226fa32d52f396a8c0383841593989dd571304602c4ac25ff162ec956b08ada52a4229546f2f1dfec69d689241f97826a72e51871e2b8658d4286ce5a0a93c4621f9e3e5994fd9bed586450aefd2f94db71c468da4af5a5ad644298e3bd6eecf352770a470ca9b6ec9f0237258a4520ade3417ce5733c94f353917c7bfbcaab1f7efdca022f90bdef7eb977f8e56bc55ec7717554fbe693bc57c9de17772eb307778a0d88e3f7c71f3cf92aeba74fdfeafd0aecf078117938ee4270789ca16c7e7d98438c901f5e3ff68e664548e1d87be1e3a359060d421e3d7ee7cdfbb342b171bcf770fffe2c2b2b8e9d1f519097d004f7e8af3f7f2ed6ca06ecbff1a458117393b94b7ffa6dbbc67b3708c9ef1b78eb39c305a5b2ecb427ff024faa597d0001 DMLOG START_BLOCK 5 DMLOG CREATION_OP ROOT 0 DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"eosio","net_usage":{"last_ordinal":1262304004,"value_ex":101996,"consumed":1},"cpu_usage":{"last_ordinal":1262304004,"value_ex":280111,"consumed":101},"ram_usage":199629} @@ -187,4 +187,4 @@ DMLOG RLIMIT_OP ACCOUNT_USAGE UPD {"owner":"alice","net_usage":{"last_ordinal":1 DMLOG APPLIED_TRANSACTION 5 c2e8f254cf27feb007d7f43ed2cf9f20b4993f425de7b4632997cb7f49de509705000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d320100d007000012000000000000000090000000000000000001010000010000000000ea3055f3d881d2f7fbf2f7cb6081aff84e7aca1dd3914a0948ef4fc9422e734e8d4d571e000000000000001e00000000000000010000000000855c34010000000000000002020000000000ea30550000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed323201000000000000000000000000c2e8f254cf27feb007d7f43ed2cf9f20b4993f425de7b4632997cb7f49de509705000000043b3d4b010000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d32010000000000855c34400100000000000000000000000000 DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":4,"value_ex":146193333,"consumed":8009},"average_block_cpu_usage":{"last_ordinal":4,"value_ex":399423669,"consumed":4466},"pending_net_usage":376,"pending_cpu_usage":4100,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1051726,"virtual_cpu_limit":200600} DMLOG RLIMIT_OP STATE UPD {"average_block_net_usage":{"last_ordinal":5,"value_ex":148108389,"consumed":521},"average_block_cpu_usage":{"last_ordinal":5,"value_ex":430261805,"consumed":4497},"pending_net_usage":0,"pending_cpu_usage":0,"total_net_weight":0,"total_cpu_weight":0,"total_ram_bytes":0,"virtual_net_limit":1052778,"virtual_cpu_limit":200800} -DMLOG ACCEPTED_BLOCK 5 05000000050000000400000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100013a220582e0cfa7a17f55cebb532b2a1d90d2ef2ae30469faa539ba199e2244a40400000000000000010000000000ea305505000000010000000000ea305504000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d32043b3d4b0000000000ea3055000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e56cbb1751058d6346085c90810b9506a2813958022794c157d0182253441a192032e84b542636e8b3efa7359943ee5c039d3ae19fbeb432871652ecfdc57fb22d000000000000001f78ee459e123dba62f8d8ae4168bec01f85253e5d30cc245bedf803fe712c5680524933231df7361e5d18731b8c0a44f48a696cc74dfd22755d41f031787509330000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001150ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fccad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001043b3d4b0000000000ea3055000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e56cbb1751058d6346085c90810b9506a2813958022794c157d0182253441a192032e84b542636e8b3efa7359943ee5c039d3ae19fbeb432871652ecfdc57fb22d000000000000001f78ee459e123dba62f8d8ae4168bec01f85253e5d30cc245bedf803fe712c5680524933231df7361e5d18731b8c0a44f48a696cc74dfd22755d41f031787509330200d00700001d0101002018a75bd433fc0c63bdc343b1b68346656c45b3700cf701b9d12fda5600ba097641950d06262f8e4b03976ebe137be9eb3d186ebf69066e9a7104228ed968d9120000bd0107e10b5e04002f98b2d600000000010000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea30550100000000d0070000120101001f0de388764e716146ab616ff095376ef69daf2fd6c2f244e0f69ad985857da8772a682aaa81862225fd75f739faf1cdb5879e4bbf2ce6133f7aed2f8d2ff4fe5700006307e10b5e04002f98b2d600000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed3232010000000001 +DMLOG ACCEPTED_BLOCK 5 05000000050000000400000000000000010000000000ea3055000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add8010000000000013a220582e0cfa7a17f55cebb532b2a1d90d2ef2ae30469faa539ba199e2244a40400000000000000010000000000ea305505000000010000000000ea305504000000000100000001000240e54a7b27e042b80a810153bec1dd166eef95fa69f6c9886ae283363bc2add80100000000000561f8cbc8bd40df6d1ad8514946e23c3fa752ea31c29ed774509e0d32043b3d4b0000000000ea3055000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e56cbb1751058d6346085c90810b9506a2813958022794c157d0182253441a192032e84b542636e8b3efa7359943ee5c039d3ae19fbeb432871652ecfdc57fb22d000000000000001f78ee459e123dba62f8d8ae4168bec01f85253e5d30cc245bedf803fe712c5680524933231df7361e5d18731b8c0a44f48a696cc74dfd22755d41f031787509330000000029807708239aa7de914d3ed61e9009ab2280bfbc50f1d9769f27f8341ef26198000000000001150ec7e080177b2c02b278d5088611686b49d739925a92d9bfcacd7fc6b74053bd1a99a59d87e06e09ec5b028a9cbb7749b4a5ad8819004365d02dc4379a8b72412652f5f96006294109b3dd0bbde63693f55324af452b799ee137a81a905eed25299dcb6af692324b899b39f16d5a530a33062804e41f09dc97e9f156b447670735c2186cc36f7bb4aeaf4487b36e57039ccf45a9136aa856a5d569ecca55ef2b4a90c00d55454dc5b059055ca213579c6ea856967712a56017487886a4d4cc0f4e7bf348da00a945489b2a681749eb56f5de00b900014e137ddae39f48f69d674fca8bd82bbd181e714e283f83e1b45d95ca5af40fb89ad3977b653c448f78c25443fcf88330c586bc0e5f3dee10e7f63c76c00249c87fe4fbf7f38c082006b468dcaa34c0517d19666e6b33add67351d8c5f69e999ca1e37931bc410a2974286bcb40a24e49c26d0a60513b6aeb8551d264e4717f306b81a37a5afb3b47cedc8ba52fe7a3956c5cd3a656a3174b931d3bb2abb45578befc59f283ecd816a40598c4175db53ed27e7911a1b5adf0e7db0fc96c2cae172cf594dfa9a742ca9e88a9cb566f982145ebccca8dcb6d2fe89b91dbd445c32ecef873cdc5d594279fccad9e3d8f650687709fd68f4b90b41f7d825a365b02c23a636cef88ac2ac00c43bcd2a26394b36614fd4894241d3c451ab0f6fd110958c3423073621a70826e99c3a6138c5061cf291310887c0b5c71fcaffeab90d5deb50d3b9e687cead45071d528b9f6e9693f45ed277af93474fd473ce7d831dae2180cca35d907bd10cb40e0fb64b1085cc5538970158d05a009c24e276fb94e1a0bf6a528b48fbc4ff526ef43112c6543b88db2283a2e077278c315ae2c84719a8b25f25cc88565fbea99f0af56d2c5a48d60a4a5b5c903edfb7db3a736a94ed589d0b797df33ff9d3e1d0001043b3d4b0000000000ea3055000000000004f5b1c8962f98b2d6155f6d21977938d545d83ef187d93aaf83e483e56cbb1751058d6346085c90810b9506a2813958022794c157d0182253441a192032e84b542636e8b3efa7359943ee5c039d3ae19fbeb432871652ecfdc57fb22d000000000000001f78ee459e123dba62f8d8ae4168bec01f85253e5d30cc245bedf803fe712c5680524933231df7361e5d18731b8c0a44f48a696cc74dfd22755d41f031787509330200d00700001d0101002018a75bd433fc0c63bdc343b1b68346656c45b3700cf701b9d12fda5600ba097641950d06262f8e4b03976ebe137be9eb3d186ebf69066e9a7104228ed968d9120000bd0107e10b5e04002f98b2d600000000010000000000ea305500409e9a2264b89a010000000000ea305500000000a8ed32328a010000000000ea30550000000000855c3401000000010002bb30f6894f29bb6fca635b1df728ad77e48fdd6123ce5e4455b0f71e072e7df80100010000000000855c3400804a1401ea305501000001000000010003ebcf44b45a71d4f225768f602d1e2e2b25ef779ee9897fe744bf1a16e85423d50100010000000000855c3400804a1401ea30550100000000d0070000120101001f0de388764e716146ab616ff095376ef69daf2fd6c2f244e0f69ad985857da8772a682aaa81862225fd75f739faf1cdb5879e4bbf2ce6133f7aed2f8d2ff4fe5700006307e10b5e04002f98b2d600000000010000000000ea30550040cbdaa86c52d5010000000000855c3400000000a8ed3232310000000000855c34000000008090b1ca00000000a8ed32320100000000010000000000ea305500000000a8ed3232010000000001 From b92aa6a31e8a3be732c103ba58fee6a57ad479fc Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 5 Sep 2023 18:09:43 -0500 Subject: [PATCH 136/151] GH-1523 Comment out test until it can be worked under GH-1558 --- unittests/snapshot_tests.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/unittests/snapshot_tests.cpp b/unittests/snapshot_tests.cpp index 5e25220161..19f8daed91 100644 --- a/unittests/snapshot_tests.cpp +++ b/unittests/snapshot_tests.cpp @@ -421,6 +421,8 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_compatible_versions, SNAPSHOT_SUITE, snapshot std::string current_version = "v6"; +#warning update test for v7 + /* int ordinal = 0; for(std::string version : {"v2", "v3", "v4" , "v5", "v6"}) { @@ -451,6 +453,7 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(test_compatible_versions, SNAPSHOT_SUITE, snapshot SNAPSHOT_SUITE::write_to_file("snap_" + current_version, latest); } + */ } /* From 77a193589f77122f454303a6472cd5cb98b25115 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Tue, 5 Sep 2023 19:09:00 -0500 Subject: [PATCH 137/151] GH-1523 Update test for base64 encoding --- libraries/libfc/test/test_bls.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 5e5dd2a071..cd571d1735 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -327,9 +327,9 @@ BOOST_AUTO_TEST_CASE(bls_prefix_encoding_check) try { } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_CASE(bls_variant) try { - bls_private_key prk("PVT_BLS_M6m7EUvzEbQErhkKUrsA96VGpdM3R3MTDszXnywcwPCt3XAcG"); - bls_public_key pk("PUB_BLS_ZCYDaAqkbBChfXcFaa6QKvy3eiGuHtF3oZ9qJUqedttU9xQFESheHMjw1wEzFTXfoJaTHsu"); - bls_signature sig("SIG_BLS_7dJV81MchymhckRBjZzJGPq5hySbAMrvhhWpvAou86YjhbpMuTm2RTcij1kxHuf1M1ew3PW3dVxKv8LZxntYF5c7S7TsoemqmJmnUUyGUpd8Pvs58eDREExQoHE5q2PZwaXiPVN3o"); + bls_private_key prk("PVT_BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"); + bls_public_key pk("PUB_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="); + bls_signature sig("SIG_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="); fc::variant v; std::string s; From 0d585203f95bb227ac6cf8a15bdf362ffb08a416 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 6 Sep 2023 08:01:15 -0400 Subject: [PATCH 138/151] change to use raw affine little endian format for POP --- programs/leap-util/actions/bls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/leap-util/actions/bls.cpp b/programs/leap-util/actions/bls.cpp index ac7a1fa645..c23a8da954 100644 --- a/programs/leap-util/actions/bls.cpp +++ b/programs/leap-util/actions/bls.cpp @@ -117,7 +117,7 @@ int bls_actions::create_pop() { std::string bls_actions::generate_pop_str(const bls_private_key& private_key) { const bls_public_key public_key = private_key.get_public_key(); - const std::array msg = public_key._pkey.toCompressedBytesBE(); + const std::array msg = public_key._pkey.toAffineBytesLE(true); // true means raw const std::vector msg_vector = std::vector(msg.begin(), msg.end()); const bls_signature pop = private_key.sign(msg_vector); From 4ae53d1d7beaa0454e101ed9ecbf83cb7886a0b9 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 6 Sep 2023 08:25:53 -0400 Subject: [PATCH 139/151] replace std::endl with \n and add -f to create key error text --- programs/leap-util/actions/bls.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/programs/leap-util/actions/bls.cpp b/programs/leap-util/actions/bls.cpp index c23a8da954..4ed94834b7 100644 --- a/programs/leap-util/actions/bls.cpp +++ b/programs/leap-util/actions/bls.cpp @@ -43,10 +43,10 @@ void bls_actions::setup(CLI::App& app) { int bls_actions::create_key() { if (opt->key_file.empty() && !opt->print_console) { - std::cerr << "ERROR: Either indicate a file using \"--file\" or pass \"--to-console\"" << std::endl; + std::cerr << "ERROR: Either indicate a file using \"-f, --file\" or pass \"--to-console\"" << "\n"; return -1; } else if (!opt->key_file.empty() && opt->print_console) { - std::cerr << "ERROR: Only one of \"--file\" or pass \"--to-console\" can be provided" << std::endl; + std::cerr << "ERROR: Only one of \"-f, --file\" or pass \"--to-console\" can be provided" << "\n"; return -1; } @@ -64,7 +64,7 @@ int bls_actions::create_key() { if (opt->print_console) { std::cout << out_str; } else { - std::cout << "saving keys to " << opt->key_file << std::endl; + std::cout << "saving keys to " << opt->key_file << "\n"; std::ofstream out( opt->key_file.c_str() ); out << out_str; } @@ -74,10 +74,10 @@ int bls_actions::create_key() { int bls_actions::create_pop() { if (opt->key_file.empty() && opt->private_key_str.empty()) { - std::cerr << "ERROR: Either indicate a file using \"-f, --file\" or pass \"--private-key\"" << std::endl; + std::cerr << "ERROR: Either indicate a file using \"-f, --file\" or pass \"--private-key\"" << "\n"; return -1; } else if (!opt->key_file.empty() && !opt->private_key_str.empty()) { - std::cerr << "ERROR: Only one of \"-f, --file\" and \"--private-key\" can be provided" << std::endl; + std::cerr << "ERROR: Only one of \"-f, --file\" and \"--private-key\" can be provided" << "\n"; return -1; } @@ -88,17 +88,17 @@ int bls_actions::create_pop() { std::ifstream key_file(opt->key_file); if (!key_file.is_open()) { - std::cerr << "ERROR: failed to open file " << opt->key_file << std::endl; + std::cerr << "ERROR: failed to open file " << opt->key_file << "\n"; return -1; } if (std::getline(key_file, private_key_str)) { if (!key_file.eof()) { - std::cerr << "ERROR: file " << opt->key_file << " contains more than one line" << std::endl; + std::cerr << "ERROR: file " << opt->key_file << " contains more than one line" << "\n"; return -1; } } else { - std::cerr << "ERROR: file " << opt->key_file << " is empty" << std::endl; + std::cerr << "ERROR: file " << opt->key_file << " is empty" << "\n"; return -1; } } @@ -108,8 +108,8 @@ int bls_actions::create_pop() { const bls_public_key public_key = private_key.get_public_key(); std::string pop_str = generate_pop_str(private_key); - std::cout << "Proof of Possession: " << pop_str << std::endl; - std::cout << "Public key: " << public_key.to_string({}) << std::endl; + std::cout << "Proof of Possession: " << pop_str << "\n"; + std::cout << "Public key: " << public_key.to_string({}) << "\n"; return 0; } From af5c9fb6decd6048b584679685a54bbd15dfbfb3 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 6 Sep 2023 08:57:08 -0400 Subject: [PATCH 140/151] use raw Affine little-endian form of g1/g2 for encoding to BLS public key and signature --- libraries/libfc/src/crypto/bls_public_key.cpp | 4 ++-- libraries/libfc/src/crypto/bls_signature.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index f137a1cce6..3ef3a208b6 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -26,9 +26,9 @@ namespace fc::crypto::blslib { std::string bls_public_key::to_string(const yield_function_t& yield)const { - std::array bytes = _pkey.toCompressedBytesBE(); + std::array bytes = _pkey.toAffineBytesLE(true); // true means raw - std::string data_str = fc::crypto::blslib::serialize_base64>(bytes); + std::string data_str = fc::crypto::blslib::serialize_base64>(bytes); return config::bls_public_key_prefix + data_str; diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index bab437b521..6e03f18bc9 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -31,9 +31,9 @@ namespace fc::crypto::blslib { std::string bls_signature::to_string(const yield_function_t& yield) const { - std::array bytes = _sig.toCompressedBytesBE(); + std::array bytes = _sig.toAffineBytesLE(true); // true means raw - std::string data_str = fc::crypto::blslib::serialize_base64>(bytes); + std::string data_str = fc::crypto::blslib::serialize_base64>(bytes); return config::bls_signature_prefix + data_str; @@ -56,4 +56,4 @@ namespace fc { vo = crypto::blslib::bls_signature(var.as_string()); } -} // fc \ No newline at end of file +} // fc From 560b3f706f0d16e840c3bd9f0b841d1e523f4a32 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 6 Sep 2023 11:20:18 -0500 Subject: [PATCH 141/151] GH-1523 Update forkdb version since not backward compatible. --- libraries/chain/fork_database.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libraries/chain/fork_database.cpp b/libraries/chain/fork_database.cpp index 9a7f863914..57bab920b2 100644 --- a/libraries/chain/fork_database.cpp +++ b/libraries/chain/fork_database.cpp @@ -17,8 +17,8 @@ namespace eosio { namespace chain { const uint32_t fork_database::magic_number = 0x30510FDB; - const uint32_t fork_database::min_supported_version = 1; - const uint32_t fork_database::max_supported_version = 1; + const uint32_t fork_database::min_supported_version = 2; + const uint32_t fork_database::max_supported_version = 2; // work around block_state::is_valid being private inline bool block_state_is_valid( const block_state& bs ) { @@ -28,6 +28,7 @@ namespace eosio { namespace chain { /** * History: * Version 1: initial version of the new refactored fork database portable format + * Version 2: New format for block_state for hotstuff/instant-finality */ struct by_block_id; From ef2f3784a983793073b510f500f5b9e7f49576d8 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 6 Sep 2023 11:24:05 -0500 Subject: [PATCH 142/151] GH-1523 Add option to producer_plugin to specify BLS finalizer keys --- libraries/hotstuff/chain_pacemaker.cpp | 7 +- .../eosio/hotstuff/chain_pacemaker.hpp | 5 +- .../include/eosio/hotstuff/qc_chain.hpp | 6 +- libraries/hotstuff/qc_chain.cpp | 6 +- libraries/hotstuff/test/test_hotstuff.cpp | 2 +- plugins/chain_plugin/chain_plugin.cpp | 4 +- .../eosio/chain_plugin/chain_plugin.hpp | 2 +- plugins/producer_plugin/producer_plugin.cpp | 16 +++- .../signature_provider_plugin.hpp | 10 ++- .../signature_provider_plugin.cpp | 77 ++++++++++++------- 10 files changed, 94 insertions(+), 41 deletions(-) diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 3110458214..b0fa8f6eba 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -101,9 +101,12 @@ namespace eosio { namespace hotstuff { #endif //=============================================================================================== - chain_pacemaker::chain_pacemaker(controller* chain, std::set my_producers, fc::logger& logger) + chain_pacemaker::chain_pacemaker(controller* chain, + std::set my_producers, + std::map finalizer_keys, + fc::logger& logger) : _chain(chain), - _qc_chain("default"_n, this, std::move(my_producers), logger), + _qc_chain("default"_n, this, std::move(my_producers), std::move(finalizer_keys), logger), _logger(logger) { _accepted_block_connection = chain->accepted_block.connect( [this]( const block_state_ptr& blk ) { diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index 70320adc11..fcc8ea51c1 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -20,7 +20,10 @@ namespace eosio::hotstuff { //class-specific functions - chain_pacemaker(controller* chain, std::set my_producers, fc::logger& logger); + chain_pacemaker(controller* chain, + std::set my_producers, + std::map finalizer_keys, + fc::logger& logger); void register_bcast_function(std::function broadcast_hs_message); void beat(); diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index c410d7d769..32a8a9be82 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -95,7 +95,10 @@ namespace eosio::hotstuff { qc_chain() = delete; - qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, fc::logger& logger); + qc_chain(name id, base_pacemaker* pacemaker, + std::set my_producers, + std::map finalizer_keys, + fc::logger& logger); uint64_t get_state_version() const { return _state_version; } // calling this w/ thread sync is optional @@ -195,6 +198,7 @@ namespace eosio::hotstuff { eosio::chain::extended_schedule _schedule; base_pacemaker* _pacemaker = nullptr; std::set _my_producers; + std::map _my_finalizer_keys; name _id; mutable std::atomic _state_version = 1; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 2ee77ad3b1..3e5a45dfc5 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -235,9 +235,13 @@ namespace eosio::hotstuff { } - qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, fc::logger& logger) + qc_chain::qc_chain(name id, base_pacemaker* pacemaker, + std::set my_producers, + std::map finalizer_keys, + fc::logger& logger) : _pacemaker(pacemaker), _my_producers(std::move(my_producers)), + _my_finalizer_keys(std::move(finalizer_keys)), _id(id), _logger(logger) { diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index cba5789a39..997708fe91 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -53,7 +53,7 @@ class hotstuff_test_handler { //_qc_chains.reserve( replicas.size() ); for (name r : replicas) { - qc_chain *qcc_ptr = new qc_chain(r, &tpm, {r}, hotstuff_logger); + qc_chain *qcc_ptr = new qc_chain(r, &tpm, {r}, {}, hotstuff_logger); std::shared_ptr qcc_shared_ptr(qcc_ptr); _qc_chains.push_back( std::make_pair(r, qcc_shared_ptr) ); diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 2743d01a90..4b4ee5ac10 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1117,9 +1117,9 @@ void chain_plugin_impl::plugin_initialize(const variables_map& options) { } FC_LOG_AND_RETHROW() } -void chain_plugin::create_pacemaker(std::set my_producers) { +void chain_plugin::create_pacemaker(std::set my_producers, std::map finalizer_keys) { EOS_ASSERT( !my->_chain_pacemaker, plugin_config_exception, "duplicate chain_pacemaker initialization" ); - my->_chain_pacemaker.emplace(&chain(), std::move(my_producers), hotstuff_logger); + my->_chain_pacemaker.emplace(&chain(), std::move(my_producers), std::move(finalizer_keys), hotstuff_logger); } void chain_plugin::register_pacemaker_bcast_function(std::function bcast_hs_message) { diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index e09b6d6aab..031255ce3d 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -1031,7 +1031,7 @@ class chain_plugin : public plugin { // Only call this after plugin_initialize()! const controller& chain() const; - void create_pacemaker(std::set my_producers); + void create_pacemaker(std::set my_producers, std::map finalizer_keys); void register_pacemaker_bcast_function(std::function bcast_hs_message); void notify_hs_message( const chain::hs_message& msg ); void notify_hs_block_produced(); diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index fba71dcf6c..45cd3a0666 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -519,6 +519,7 @@ class producer_plugin_impl : public std::enable_shared_from_this _signature_providers; + std::map _finalizer_keys; std::set _producers; boost::asio::deadline_timer _timer; block_timing_util::producer_watermarks _producer_watermarks; @@ -1136,8 +1137,16 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia const std::vector key_spec_pairs = options["signature-provider"].as>(); for (const auto& key_spec_pair : key_spec_pairs) { try { - const auto& [pubkey, provider] = app().get_plugin().signature_provider_for_specification(key_spec_pair); - _signature_providers[pubkey] = provider; + const auto v = app().get_plugin().signature_provider_for_specification(key_spec_pair); + if (v) { + const auto& [pubkey, provider] = *v; + _signature_providers[pubkey] = provider; + } + const auto bls = app().get_plugin().bls_public_key_for_specification(key_spec_pair); + if (bls) { + const auto& [pubkey, privkey] = *bls; + _finalizer_keys[pubkey] = privkey; + } } catch(secure_enclave_exception& e) { elog("Error with Secure Enclave signature provider: ${e}; ignoring ${val}", ("e", e.top_message())("val", key_spec_pair)); } catch (fc::exception& e) { @@ -1358,7 +1367,8 @@ void producer_plugin_impl::plugin_startup() { EOS_ASSERT(_producers.empty() || chain_plug->accept_transactions(), plugin_config_exception, "node cannot have any producer-name configured because no block production is possible with no [api|p2p]-accepted-transactions"); - chain_plug->create_pacemaker(_producers); + chain_plug->create_pacemaker(_producers, std::move(_finalizer_keys)); + _finalizer_keys.clear(); _accepted_block_connection.emplace(chain.accepted_block.connect([this](const auto& bsp) { on_block(bsp); })); _accepted_block_header_connection.emplace(chain.accepted_block_header.connect([this](const auto& bsp) { on_block_header(bsp); })); diff --git a/plugins/signature_provider_plugin/include/eosio/signature_provider_plugin/signature_provider_plugin.hpp b/plugins/signature_provider_plugin/include/eosio/signature_provider_plugin/signature_provider_plugin.hpp index 14fbc6f6e6..5378bb4cdd 100644 --- a/plugins/signature_provider_plugin/include/eosio/signature_provider_plugin/signature_provider_plugin.hpp +++ b/plugins/signature_provider_plugin/include/eosio/signature_provider_plugin/signature_provider_plugin.hpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include namespace eosio { @@ -23,8 +25,12 @@ class signature_provider_plugin : public appbase::plugin; - std::pair signature_provider_for_specification(const std::string& spec) const; - signature_provider_type signature_provider_for_private_key(const chain::private_key_type priv) const; + // @return empty optional for BLS specs + std::optional> signature_provider_for_specification(const std::string& spec) const; + signature_provider_type signature_provider_for_private_key(const chain::private_key_type& priv) const; + + // @return empty optional for non-BLS specs + std::optional> bls_public_key_for_specification(const std::string& spec) const; private: std::unique_ptr my; diff --git a/plugins/signature_provider_plugin/signature_provider_plugin.cpp b/plugins/signature_provider_plugin/signature_provider_plugin.cpp index 2d4e31d9be..a9bf9277be 100644 --- a/plugins/signature_provider_plugin/signature_provider_plugin.cpp +++ b/plugins/signature_provider_plugin/signature_provider_plugin.cpp @@ -37,6 +37,38 @@ class signature_provider_plugin_impl { return app().get_plugin().get_client().post_sync(keosd_url, params, deadline).as(); }; } + + // public_key spec_type spec_data + std::tuple parse_spec(const std::string& spec) const { + auto delim = spec.find("="); + EOS_ASSERT(delim != std::string::npos, chain::plugin_config_exception, "Missing \"=\" in the key spec pair"); + auto pub_key_str = spec.substr(0, delim); + auto spec_str = spec.substr(delim + 1); + + auto spec_delim = spec_str.find(":"); + EOS_ASSERT(spec_delim != std::string::npos, chain::plugin_config_exception, "Missing \":\" in the key spec pair"); + auto spec_type_str = spec_str.substr(0, spec_delim); + auto spec_data = spec_str.substr(spec_delim + 1); + return {std::move(pub_key_str), std::move(spec_type_str), std::move(spec_data)}; + } + + std::optional> + signature_provider_for_specification(const std::string& spec) const { + auto [pub_key_str, spec_type_str, spec_data] = parse_spec(spec); + if( pub_key_str.starts_with("PUB_BLS") && spec_type_str == "KEY" ) + return {}; + + auto pubkey = chain::public_key_type(pub_key_str); + + if(spec_type_str == "KEY") { + chain::private_key_type priv(spec_data); + EOS_ASSERT(pubkey == priv.get_public_key(), chain::plugin_config_exception, "Private key does not match given public key for ${pub}", ("pub", pubkey)); + return std::make_pair(pubkey, make_key_signature_provider(priv)); + } + else if(spec_type_str == "KEOSD") + return std::make_pair(pubkey, make_keosd_signature_provider(spec_data, pubkey)); + EOS_THROW(chain::plugin_config_exception, "Unsupported key provider type \"${t}\"", ("t", spec_type_str)); + } }; signature_provider_plugin::signature_provider_plugin():my(new signature_provider_plugin_impl()){} @@ -52,11 +84,11 @@ void signature_provider_plugin::set_program_options(options_description&, option const char* const signature_provider_plugin::signature_provider_help_text() const { return "Key=Value pairs in the form =\n" "Where:\n" - " \tis a string form of a vaild EOSIO public key\n\n" - " \tis a string in the form :\n\n" - " \tis KEY, KEOSD, or SE\n\n" - " KEY: \tis a string form of a valid EOSIO private key which maps to the provided public key\n\n" - " KEOSD: \tis the URL where keosd is available and the approptiate wallet(s) are unlocked\n\n" + " \tis a string form of a vaild Antelope public key, including BLS finalizer key\n" + " \tis a string in the form :\n" + " \tis KEY, KEOSD, or SE\n" + " KEY: \tis a string form of a valid Antelope private key which maps to the provided public key\n" + " KEOSD: \tis the URL where keosd is available and the appropriate wallet(s) are unlocked\n\n" ; } @@ -65,33 +97,24 @@ void signature_provider_plugin::plugin_initialize(const variables_map& options) my->_keosd_provider_timeout_us = fc::milliseconds( options.at("keosd-provider-timeout").as() ); } -std::pair + +std::optional> signature_provider_plugin::signature_provider_for_specification(const std::string& spec) const { - auto delim = spec.find("="); - EOS_ASSERT(delim != std::string::npos, chain::plugin_config_exception, "Missing \"=\" in the key spec pair"); - auto pub_key_str = spec.substr(0, delim); - auto spec_str = spec.substr(delim + 1); - - auto spec_delim = spec_str.find(":"); - EOS_ASSERT(spec_delim != std::string::npos, chain::plugin_config_exception, "Missing \":\" in the key spec pair"); - auto spec_type_str = spec_str.substr(0, spec_delim); - auto spec_data = spec_str.substr(spec_delim + 1); - - auto pubkey = chain::public_key_type(pub_key_str); - - if(spec_type_str == "KEY") { - chain::private_key_type priv(spec_data); - EOS_ASSERT(pubkey == priv.get_public_key(), chain::plugin_config_exception, "Private key does not match given public key for ${pub}", ("pub", pubkey)); - return std::make_pair(pubkey, my->make_key_signature_provider(priv)); - } - else if(spec_type_str == "KEOSD") - return std::make_pair(pubkey, my->make_keosd_signature_provider(spec_data, pubkey)); - EOS_THROW(chain::plugin_config_exception, "Unsupported key provider type \"${t}\"", ("t", spec_type_str)); + return my->signature_provider_for_specification(spec); } signature_provider_plugin::signature_provider_type -signature_provider_plugin::signature_provider_for_private_key(const chain::private_key_type priv) const { +signature_provider_plugin::signature_provider_for_private_key(const chain::private_key_type& priv) const { return my->make_key_signature_provider(priv); } +std::optional> +signature_provider_plugin::bls_public_key_for_specification(const std::string& spec) const { + auto [pub_key_str, spec_type_str, spec_data] = my->parse_spec(spec); + if( pub_key_str.starts_with("PUB_BLS") && spec_type_str == "KEY" ) { + return std::make_pair(fc::crypto::blslib::bls_public_key{pub_key_str}, fc::crypto::blslib::bls_private_key{spec_data}); + } + return {}; } + +} // namespace eosio From 9de9f6aa7a6923762fa38e201e77ee7eca7cb013 Mon Sep 17 00:00:00 2001 From: Dmytro Sydorchenko Date: Wed, 6 Sep 2023 14:10:40 -0400 Subject: [PATCH 143/151] added set_finalizers to host functions list --- .../eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp | 3 ++- libraries/chain/webassembly/runtimes/eos-vm.cpp | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp index ea92a9cf86..6d8b9b5141 100644 --- a/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp +++ b/libraries/chain/include/eosio/chain/webassembly/eos-vm-oc/intrinsic_mapping.hpp @@ -277,7 +277,8 @@ inline constexpr auto get_intrinsic_table() { "env.bls_pairing", "env.bls_g1_map", "env.bls_g2_map", - "env.bls_fp_mod" + "env.bls_fp_mod", + "env.set_finalizers" ); } inline constexpr std::size_t find_intrinsic_index(std::string_view hf) { diff --git a/libraries/chain/webassembly/runtimes/eos-vm.cpp b/libraries/chain/webassembly/runtimes/eos-vm.cpp index e23f91b90e..d0eaea4b32 100644 --- a/libraries/chain/webassembly/runtimes/eos-vm.cpp +++ b/libraries/chain/webassembly/runtimes/eos-vm.cpp @@ -357,6 +357,7 @@ REGISTER_LEGACY_HOST_FUNCTION(get_blockchain_parameters_packed, privileged_check REGISTER_LEGACY_HOST_FUNCTION(set_blockchain_parameters_packed, privileged_check); REGISTER_HOST_FUNCTION(is_privileged, privileged_check); REGISTER_HOST_FUNCTION(set_privileged, privileged_check); +REGISTER_HOST_FUNCTION(set_finalizers, privileged_check); // softfloat api REGISTER_INJECTED_HOST_FUNCTION(_eosio_f32_add); From 4d01e5fbb4491aa682e56739a5844b6209a0ee75 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Wed, 6 Sep 2023 15:03:33 -0400 Subject: [PATCH 144/151] Update conversion from string to public key and signatur, and update tests --- libraries/libfc/src/crypto/bls_public_key.cpp | 9 ++-- libraries/libfc/src/crypto/bls_signature.cpp | 9 ++-- libraries/libfc/test/test_bls.cpp | 41 +++++++++---------- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index 3ef3a208b6..d953d77be5 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -13,9 +13,11 @@ namespace fc::crypto::blslib { auto data_str = base64str.substr(config::bls_public_key_prefix.size()); - std::array bytes = fc::crypto::blslib::deserialize_base64>(data_str); + std::array bytes = fc::crypto::blslib::deserialize_base64>(data_str); - std::optional g1 = bls12_381::g1::fromCompressedBytesBE(bytes); + constexpr bool check = false; // default + constexpr bool raw = true; + std::optional g1 = bls12_381::g1::fromAffineBytesLE(bytes, check, raw); FC_ASSERT(g1); return *g1; } @@ -26,7 +28,8 @@ namespace fc::crypto::blslib { std::string bls_public_key::to_string(const yield_function_t& yield)const { - std::array bytes = _pkey.toAffineBytesLE(true); // true means raw + constexpr bool raw = true; + std::array bytes = _pkey.toAffineBytesLE(raw); std::string data_str = fc::crypto::blslib::serialize_base64>(bytes); diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 6e03f18bc9..97bd8cc7b6 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -15,9 +15,11 @@ namespace fc::crypto::blslib { auto data_str = base64str.substr(config::bls_signature_prefix.size()); - std::array bytes = fc::crypto::blslib::deserialize_base64>(data_str); + std::array bytes = fc::crypto::blslib::deserialize_base64>(data_str); - std::optional g2 = bls12_381::g2::fromCompressedBytesBE(bytes); + constexpr bool check = false; // default + constexpr bool raw = true; + std::optional g2 = bls12_381::g2::fromAffineBytesLE(bytes, check, raw); FC_ASSERT(g2); return *g2; @@ -31,7 +33,8 @@ namespace fc::crypto::blslib { std::string bls_signature::to_string(const yield_function_t& yield) const { - std::array bytes = _sig.toAffineBytesLE(true); // true means raw + constexpr bool raw = true; + std::array bytes = _sig.toAffineBytesLE(raw); std::string data_str = fc::crypto::blslib::serialize_base64>(bytes); diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 790e440d90..4f064399cb 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -281,48 +281,47 @@ BOOST_AUTO_TEST_CASE(bls_prefix_encoding_check) try { //test no_throw for correctly encoded keys BOOST_CHECK_NO_THROW(bls_private_key("PVT_BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x")); - BOOST_CHECK_NO_THROW(bls_public_key("PUB_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA==")); - BOOST_CHECK_NO_THROW(bls_signature("SIG_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g==")); + BOOST_CHECK_NO_THROW(bls_public_key("PUB_BLS_tCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSRg==")); + BOOST_CHECK_NO_THROW(bls_signature("SIG_BLS_Syq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ==")); //test no pivot delimiter BOOST_CHECK_THROW(bls_private_key("PVTBLSLaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUBBLShiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("SIGBLSqn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUBBLStCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSRg=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIGBLSSyq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ=="), fc::assert_exception); //test first prefix validation BOOST_CHECK_THROW(bls_private_key("XYZ_BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("XYZ_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("XYZ_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("XYZ_BLS_tCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSRg=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("XYZ_BLS_Syq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ=="), fc::assert_exception); //test second prefix validation BOOST_CHECK_THROW(bls_private_key("PVT_XYZ_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_XYZ_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("SIG_XYZ_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_XYZ_tCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSRg=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_XYZ_Syq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ=="), fc::assert_exception); //test missing prefix BOOST_CHECK_THROW(bls_private_key("LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("tCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSRg=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("Syq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ=="), fc::assert_exception); //test incomplete prefix BOOST_CHECK_THROW(bls_private_key("PVT_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("SIG_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_tCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSRg=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_Syq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ=="), fc::assert_exception); BOOST_CHECK_THROW(bls_private_key("BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("BLS_tCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSRg=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("BLS_Syq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ=="), fc::assert_exception); //test invalid data / invalid checksum BOOST_CHECK_THROW(bls_private_key("PVT_BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+y"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFBA=="), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("SIG_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS8g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_BLS_tCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSSg=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_BLS_Syq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQxQ=="), fc::assert_exception); BOOST_CHECK_THROW(bls_private_key("PVT_BLS_LaNRcYuQxSm/tRrMofQduPb5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpnwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("SIG_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqQ8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_public_key("PUB_BLS_tCPHD1uL85ZWAX8yY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSRg=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_BLS_Syq5e23eMxcXnSGud+ACcKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ=="), fc::assert_exception); BOOST_CHECK_THROW(bls_private_key("PVT_BLS_MaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"), fc::assert_exception); - BOOST_CHECK_THROW(bls_public_key("PUB_BLS_iiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="), fc::assert_exception); - BOOST_CHECK_THROW(bls_signature("SIG_BLS_rn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="), fc::assert_exception); - + BOOST_CHECK_THROW(bls_public_key("PUB_BLS_uCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSSg=="), fc::assert_exception); + BOOST_CHECK_THROW(bls_signature("SIG_BLS_Tyq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ=="), fc::assert_exception); } FC_LOG_AND_RETHROW(); BOOST_AUTO_TEST_SUITE_END() From 01f462d0348d38ed8f1634404983dfc4b435f292 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Wed, 6 Sep 2023 15:20:58 -0500 Subject: [PATCH 145/151] GH-1523 Use alias for bls_key_map_t --- libraries/chain/include/eosio/chain/hotstuff.hpp | 1 + libraries/hotstuff/chain_pacemaker.cpp | 2 +- libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp | 2 +- libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp | 4 ++-- libraries/hotstuff/qc_chain.cpp | 2 +- plugins/chain_plugin/chain_plugin.cpp | 2 +- .../chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp | 2 +- plugins/producer_plugin/producer_plugin.cpp | 2 +- .../signature_provider_plugin/signature_provider_plugin.cpp | 2 +- 9 files changed, 10 insertions(+), 9 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index 2db473827d..b580387d51 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -11,6 +11,7 @@ namespace eosio::chain { using hs_bitset = boost::dynamic_bitset; + using bls_key_map_t = std::map; inline uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) { return (uint64_t{block_height} << 32) | phase_counter; diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index b0fa8f6eba..2940f08cc8 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -103,7 +103,7 @@ namespace eosio { namespace hotstuff { chain_pacemaker::chain_pacemaker(controller* chain, std::set my_producers, - std::map finalizer_keys, + bls_key_map_t finalizer_keys, fc::logger& logger) : _chain(chain), _qc_chain("default"_n, this, std::move(my_producers), std::move(finalizer_keys), logger), diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index fcc8ea51c1..c2c2331278 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -22,7 +22,7 @@ namespace eosio::hotstuff { chain_pacemaker(controller* chain, std::set my_producers, - std::map finalizer_keys, + chain::bls_key_map_t finalizer_keys, fc::logger& logger); void register_bcast_function(std::function broadcast_hs_message); diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index 32a8a9be82..e696280009 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -97,7 +97,7 @@ namespace eosio::hotstuff { qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, - std::map finalizer_keys, + chain::bls_key_map_t finalizer_keys, fc::logger& logger); uint64_t get_state_version() const { return _state_version; } // calling this w/ thread sync is optional @@ -198,7 +198,7 @@ namespace eosio::hotstuff { eosio::chain::extended_schedule _schedule; base_pacemaker* _pacemaker = nullptr; std::set _my_producers; - std::map _my_finalizer_keys; + chain::bls_key_map_t _my_finalizer_keys; name _id; mutable std::atomic _state_version = 1; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index 3e5a45dfc5..e62381fb0e 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -237,7 +237,7 @@ namespace eosio::hotstuff { qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set my_producers, - std::map finalizer_keys, + bls_key_map_t finalizer_keys, fc::logger& logger) : _pacemaker(pacemaker), _my_producers(std::move(my_producers)), diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index 4b4ee5ac10..c64962b468 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -1117,7 +1117,7 @@ void chain_plugin_impl::plugin_initialize(const variables_map& options) { } FC_LOG_AND_RETHROW() } -void chain_plugin::create_pacemaker(std::set my_producers, std::map finalizer_keys) { +void chain_plugin::create_pacemaker(std::set my_producers, chain::bls_key_map_t finalizer_keys) { EOS_ASSERT( !my->_chain_pacemaker, plugin_config_exception, "duplicate chain_pacemaker initialization" ); my->_chain_pacemaker.emplace(&chain(), std::move(my_producers), std::move(finalizer_keys), hotstuff_logger); } diff --git a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp index 031255ce3d..e4d96b2a4a 100644 --- a/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp +++ b/plugins/chain_plugin/include/eosio/chain_plugin/chain_plugin.hpp @@ -1031,7 +1031,7 @@ class chain_plugin : public plugin { // Only call this after plugin_initialize()! const controller& chain() const; - void create_pacemaker(std::set my_producers, std::map finalizer_keys); + void create_pacemaker(std::set my_producers, chain::bls_key_map_t finalizer_keys); void register_pacemaker_bcast_function(std::function bcast_hs_message); void notify_hs_message( const chain::hs_message& msg ); void notify_hs_block_produced(); diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index 45cd3a0666..e1c13ea350 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -519,7 +519,7 @@ class producer_plugin_impl : public std::enable_shared_from_this _signature_providers; - std::map _finalizer_keys; + bls_key_map_t _finalizer_keys; std::set _producers; boost::asio::deadline_timer _timer; block_timing_util::producer_watermarks _producer_watermarks; diff --git a/plugins/signature_provider_plugin/signature_provider_plugin.cpp b/plugins/signature_provider_plugin/signature_provider_plugin.cpp index a9bf9277be..7cd9eec57d 100644 --- a/plugins/signature_provider_plugin/signature_provider_plugin.cpp +++ b/plugins/signature_provider_plugin/signature_provider_plugin.cpp @@ -84,7 +84,7 @@ void signature_provider_plugin::set_program_options(options_description&, option const char* const signature_provider_plugin::signature_provider_help_text() const { return "Key=Value pairs in the form =\n" "Where:\n" - " \tis a string form of a vaild Antelope public key, including BLS finalizer key\n" + " \tis a string form of a valid Antelope public key, including BLS finalizer key\n" " \tis a string in the form :\n" " \tis KEY, KEOSD, or SE\n" " KEY: \tis a string form of a valid Antelope private key which maps to the provided public key\n" From 2132734b92f09c058c26fee0584e91b09f4f29a6 Mon Sep 17 00:00:00 2001 From: Lin Huang Date: Thu, 7 Sep 2023 07:50:52 -0400 Subject: [PATCH 146/151] check if public key string and signature string are invlid in conversion --- libraries/libfc/src/crypto/bls_public_key.cpp | 2 +- libraries/libfc/src/crypto/bls_signature.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/libfc/src/crypto/bls_public_key.cpp b/libraries/libfc/src/crypto/bls_public_key.cpp index d953d77be5..5fa51e81f6 100644 --- a/libraries/libfc/src/crypto/bls_public_key.cpp +++ b/libraries/libfc/src/crypto/bls_public_key.cpp @@ -15,7 +15,7 @@ namespace fc::crypto::blslib { std::array bytes = fc::crypto::blslib::deserialize_base64>(data_str); - constexpr bool check = false; // default + constexpr bool check = true; // check if base64str is invalid constexpr bool raw = true; std::optional g1 = bls12_381::g1::fromAffineBytesLE(bytes, check, raw); FC_ASSERT(g1); diff --git a/libraries/libfc/src/crypto/bls_signature.cpp b/libraries/libfc/src/crypto/bls_signature.cpp index 97bd8cc7b6..9e926910c0 100644 --- a/libraries/libfc/src/crypto/bls_signature.cpp +++ b/libraries/libfc/src/crypto/bls_signature.cpp @@ -17,7 +17,7 @@ namespace fc::crypto::blslib { std::array bytes = fc::crypto::blslib::deserialize_base64>(data_str); - constexpr bool check = false; // default + constexpr bool check = true; // check if base64str is invalid constexpr bool raw = true; std::optional g2 = bls12_381::g2::fromAffineBytesLE(bytes, check, raw); FC_ASSERT(g2); From 3a4d5ad1a1562cd7aa8d1a3fd79cd332069d49fa Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 7 Sep 2023 07:17:51 -0500 Subject: [PATCH 147/151] GH-1523 Use raw Affine LE form --- libraries/chain/webassembly/privileged.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/chain/webassembly/privileged.cpp b/libraries/chain/webassembly/privileged.cpp index a447154390..5c6c172b1a 100644 --- a/libraries/chain/webassembly/privileged.cpp +++ b/libraries/chain/webassembly/privileged.cpp @@ -183,7 +183,9 @@ 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 pk = bls12_381::g1::fromAffineBytesLE(f.public_key_g1_affine_le); + constexpr bool check = false; // system contract does proof of possession check which is a stronger check + constexpr bool raw = true; + std::optional 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, @@ -191,6 +193,7 @@ namespace eosio { namespace chain { namespace webassembly { 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" ); From 7a5714d8245dca3746db2b77591fbaa2ba5771ed Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 7 Sep 2023 07:18:29 -0500 Subject: [PATCH 148/151] GH-1523 Add warning so change is not forgotten --- libraries/chain/include/eosio/chain/block_header_state.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 060c1ee943..0948d0d6e7 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -54,6 +54,7 @@ namespace detail { uint32_t dpos_proposed_irreversible_blocknum = 0; uint32_t dpos_irreversible_blocknum = 0; producer_authority_schedule active_schedule; +#warning Add to snapshot_block_header_state_v3 uint32_t last_proposed_finalizer_set_generation = 0; // TODO: Add to snapshot_block_header_state_v3 incremental_merkle blockroot_merkle; flat_map producer_to_last_produced; From b695b406bf1954ae79ba7f06090c5cc98c6e96dc Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 7 Sep 2023 07:20:50 -0500 Subject: [PATCH 149/151] GH-1523 Move warning to source file to avoid warning spam on every file --- libraries/chain/block_header_state.cpp | 2 ++ libraries/chain/include/eosio/chain/block_header_state.hpp | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/chain/block_header_state.cpp b/libraries/chain/block_header_state.cpp index e809e6d393..65fa92be3f 100644 --- a/libraries/chain/block_header_state.cpp +++ b/libraries/chain/block_header_state.cpp @@ -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, diff --git a/libraries/chain/include/eosio/chain/block_header_state.hpp b/libraries/chain/include/eosio/chain/block_header_state.hpp index 0948d0d6e7..060c1ee943 100644 --- a/libraries/chain/include/eosio/chain/block_header_state.hpp +++ b/libraries/chain/include/eosio/chain/block_header_state.hpp @@ -54,7 +54,6 @@ namespace detail { uint32_t dpos_proposed_irreversible_blocknum = 0; uint32_t dpos_irreversible_blocknum = 0; producer_authority_schedule active_schedule; -#warning Add to snapshot_block_header_state_v3 uint32_t last_proposed_finalizer_set_generation = 0; // TODO: Add to snapshot_block_header_state_v3 incremental_merkle blockroot_merkle; flat_map producer_to_last_produced; From b1bead19a5fe5aa84199f005b7db3a5ec1832a41 Mon Sep 17 00:00:00 2001 From: Kevin Heifner Date: Thu, 7 Sep 2023 07:24:40 -0500 Subject: [PATCH 150/151] GH-1523 Update test for new base64 form --- libraries/libfc/test/test_bls.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 1033f26a8c..3faa6d42e2 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -327,8 +327,8 @@ BOOST_AUTO_TEST_CASE(bls_prefix_encoding_check) try { BOOST_AUTO_TEST_CASE(bls_variant) try { bls_private_key prk("PVT_BLS_LaNRcYuQxSm/tRrMofQduPa5U2xUfdrCO0Yo5/CRcDeeHO+x"); - bls_public_key pk("PUB_BLS_hiQykLvL/ZrnW97OeYGWU1AgjrXpmwTVzSTpVa2pYfjAoWLe50C+e9xsPAYTui6xbEYFCA=="); - bls_signature sig("SIG_BLS_qn0BzfxSR4D6TK5c0MCYkX/hG4hp7NPwkEHvws4zoToZgPatfhqP8A62sEZd9gQ4FB95uVAQX04ZDj7nx85fsUdv4RtW6fxzUV2ZudfNUWRdjPX8ytXXnMEBAs6RRoF1TfiS9g=="); + bls_public_key pk("PUB_BLS_tCPHD1uL85ZWAX8xY06U00e72GZR0ux/RcB3DOFF5KV22F9eAVNAFU/enVJwLtQCG8N0v4KkwSSdoJo9ZRR042/xbiR3JgIsQmUqXoR0YyMuPcUGQbbon65ZgfsD3BkBUOPSRg=="); + bls_signature sig("SIG_BLS_Syq5e23eMxcXnSGud+ACbKp5on4Rn2kOXdrA5sH/VNS/0i8V9RG/Oq1AliFBuJsNm7Y+LT1bqh/23+mVzYs/YVJAmDUHLFjimqyyMI+5wDLUhqFxVplSlezTOc3kj7cSFJRCfpcZUhD0gPffjBkxXctiNubjdtqLUjkLr6jWGNFrxKeSOXS9elB9tn5nZT4SGzygqNLjcWCu4Bza7tC5B7djLtzr/9SEpDb3XPPCUTmm6kMmi2tWwxGRmu06MMMI2sjQwQ=="); fc::variant v; std::string s; From c8d9d38e2cb6e875e0c6f660d5f5d9777618843f Mon Sep 17 00:00:00 2001 From: Guillaume Babin-Tremblay Date: Sun, 10 Sep 2023 13:17:26 +0000 Subject: [PATCH 151/151] updated qc_chain to use bls_public_key as finalizer id, completed internal wiring for signing and signature verification --- .../chain/include/eosio/chain/hotstuff.hpp | 4 +- libraries/hotstuff/chain_pacemaker.cpp | 33 ++- .../include/eosio/hotstuff/base_pacemaker.hpp | 14 +- .../eosio/hotstuff/chain_pacemaker.hpp | 11 +- .../include/eosio/hotstuff/qc_chain.hpp | 25 +- .../include/eosio/hotstuff/test_pacemaker.hpp | 27 +- libraries/hotstuff/qc_chain.cpp | 99 ++++--- libraries/hotstuff/test/test_hotstuff.cpp | 243 ++++++++++++++++-- libraries/hotstuff/test/test_pacemaker.cpp | 38 +-- libraries/libfc/test/test_bls.cpp | 25 ++ 10 files changed, 367 insertions(+), 152 deletions(-) diff --git a/libraries/chain/include/eosio/chain/hotstuff.hpp b/libraries/chain/include/eosio/chain/hotstuff.hpp index b580387d51..eee4e63bc9 100644 --- a/libraries/chain/include/eosio/chain/hotstuff.hpp +++ b/libraries/chain/include/eosio/chain/hotstuff.hpp @@ -30,7 +30,7 @@ namespace eosio::chain { struct hs_vote_message { fc::sha256 proposal_id; //vote on proposal - name finalizer; + fc::crypto::blslib::bls_public_key finalizer_key; fc::crypto::blslib::bls_signature sig; }; @@ -84,7 +84,7 @@ namespace eosio::chain { // // @ignore quorum_met FC_REFLECT(eosio::chain::quorum_certificate_message, (proposal_id)(active_finalizers)(active_agg_sig)); FC_REFLECT(eosio::chain::extended_schedule, (producer_schedule)(bls_pub_keys)); -FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer)(sig)); +FC_REFLECT(eosio::chain::hs_vote_message, (proposal_id)(finalizer_key)(sig)); FC_REFLECT(eosio::chain::hs_proposal_message, (proposal_id)(block_id)(parent_id)(final_on_qc)(justify)(phase_counter)); FC_REFLECT(eosio::chain::hs_new_block_message, (block_id)(justify)); FC_REFLECT(eosio::chain::hs_new_view_message, (high_qc)); diff --git a/libraries/hotstuff/chain_pacemaker.cpp b/libraries/hotstuff/chain_pacemaker.cpp index 2940f08cc8..02afcce12f 100644 --- a/libraries/hotstuff/chain_pacemaker.cpp +++ b/libraries/hotstuff/chain_pacemaker.cpp @@ -106,7 +106,7 @@ namespace eosio { namespace hotstuff { bls_key_map_t finalizer_keys, fc::logger& logger) : _chain(chain), - _qc_chain("default"_n, this, std::move(my_producers), std::move(finalizer_keys), logger), + _qc_chain(std::string("default"), this, std::move(my_producers), std::move(finalizer_keys), logger), _logger(logger) { _accepted_block_connection = chain->accepted_block.connect( [this]( const block_state_ptr& blk ) { @@ -260,23 +260,38 @@ namespace eosio { namespace hotstuff { return n; } - std::vector chain_pacemaker::get_finalizers() { + std::vector chain_pacemaker::get_finalizer_keys() { -#warning FIXME: Use _active_finalizer_set in pacemaker/qc_chain. +//#warning FIXME: Use _active_finalizer_set in pacemaker/qc_chain. // _active_finalizer_set should be used std::unique_lock g( _chain_state_mutex ); block_state_ptr hbs = _head_block_state; g.unlock(); - // Old code: get eosio::name from the producer schedule + std::vector active_pub_keys; + active_pub_keys.reserve(_active_finalizer_set.finalizers.size()); + + std::transform(_active_finalizer_set.finalizers.begin(), _active_finalizer_set.finalizers.end(), active_pub_keys.begin(), [](finalizer_authority f_auth) { + return f_auth.public_key; + }); + + return active_pub_keys; + +/* // Old code: get eosio::name from the producer schedule const std::vector& pa_list = hbs->active_schedule.producers; std::vector pn_list; pn_list.reserve(pa_list.size()); std::transform(pa_list.begin(), pa_list.end(), std::back_inserter(pn_list), [](const producer_authority& p) { return p.producer_name; }); - return pn_list; + return pn_list;*/ + + //_active_finalizer_set.finalizers + + + + } block_id_type chain_pacemaker::get_current_block_id() { @@ -297,19 +312,19 @@ namespace eosio { namespace hotstuff { prof.core_out(); } - void chain_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, name id) { + void chain_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, const std::string& id) { bcast_hs_message(msg); } - void chain_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, name id) { + void chain_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, const std::string& id) { bcast_hs_message(msg); } - void chain_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, name id) { + void chain_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, const std::string& id) { bcast_hs_message(msg); } - void chain_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, name id) { + void chain_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, const std::string& id) { bcast_hs_message(msg); } diff --git a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp index 7fce189948..c12dbd8f2f 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/base_pacemaker.hpp @@ -3,6 +3,8 @@ #include #include +#include + #include namespace eosio::chain { @@ -33,13 +35,15 @@ namespace eosio::hotstuff { virtual chain::name get_proposer() = 0; virtual chain::name get_leader() = 0; virtual chain::name get_next_leader() = 0; - virtual std::vector get_finalizers() = 0; + // virtual std::vector get_finalizers() = 0; + virtual std::vector get_finalizer_keys() = 0; + //outbound communications; 'id' is the producer name (can be ignored if/when irrelevant to the implementer) - virtual void send_hs_proposal_msg(const chain::hs_proposal_message& msg, chain::name id) = 0; - virtual void send_hs_vote_msg(const chain::hs_vote_message& msg, chain::name id) = 0; - virtual void send_hs_new_view_msg(const chain::hs_new_view_message& msg, chain::name id) = 0; - virtual void send_hs_new_block_msg(const chain::hs_new_block_message& msg, chain::name id) = 0; + virtual void send_hs_proposal_msg(const chain::hs_proposal_message& msg, const std::string& id) = 0; + virtual void send_hs_vote_msg(const chain::hs_vote_message& msg, const std::string& id) = 0; + virtual void send_hs_new_view_msg(const chain::hs_new_view_message& msg, const std::string& id) = 0; + virtual void send_hs_new_block_msg(const chain::hs_new_block_message& msg, const std::string& id) = 0; }; } // namespace eosio::hotstuff diff --git a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp index c2c2331278..c636dbf59e 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/chain_pacemaker.hpp @@ -37,16 +37,17 @@ namespace eosio::hotstuff { name get_proposer(); name get_leader() ; name get_next_leader() ; - std::vector get_finalizers(); + //std::vector get_finalizers(); + std::vector get_finalizer_keys(); block_id_type get_current_block_id(); uint32_t get_quorum_threshold(); - void send_hs_proposal_msg(const hs_proposal_message& msg, name id); - void send_hs_vote_msg(const hs_vote_message& msg, name id); - void send_hs_new_view_msg(const hs_new_view_message& msg, name id); - void send_hs_new_block_msg(const hs_new_block_message& msg, name id); + void send_hs_proposal_msg(const hs_proposal_message& msg, const std::string& id); + void send_hs_vote_msg(const hs_vote_message& msg, const std::string& id); + void send_hs_new_view_msg(const hs_new_view_message& msg, const std::string& id); + void send_hs_new_block_msg(const hs_new_block_message& msg, const std::string& id); private: void on_accepted_block( const block_state_ptr& blk ); diff --git a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp index e696280009..4e658fc1e0 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp @@ -95,14 +95,14 @@ namespace eosio::hotstuff { qc_chain() = delete; - qc_chain(name id, base_pacemaker* pacemaker, + qc_chain(std::string id, base_pacemaker* pacemaker, std::set my_producers, chain::bls_key_map_t finalizer_keys, fc::logger& logger); uint64_t get_state_version() const { return _state_version; } // calling this w/ thread sync is optional - name get_id_i() const { return _id; } // so far, only ever relevant in a test environment (no sync) + std::string get_id_i() const { return _id; } // so far, only ever relevant in a test environment (no sync) // Calls to the following methods should be thread-synchronized externally: @@ -124,16 +124,16 @@ namespace eosio::hotstuff { uint32_t positive_bits_count(const hs_bitset& finalizers); - hs_bitset update_bitset(const hs_bitset& finalizer_set, name finalizer); + hs_bitset update_bitset(const hs_bitset& finalizer_set, fc::crypto::blslib::bls_public_key finalizer_key); digest_type get_digest_to_sign(const block_id_type& block_id, uint8_t phase_counter, const fc::sha256& final_on_qc); //get digest to sign from proposal data void reset_qc(const fc::sha256& proposal_id); //reset current internal qc - bool evaluate_quorum(const extended_schedule& es, const hs_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal + bool evaluate_quorum(const hs_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal); //evaluate quorum for a proposal // qc.quorum_met has to be updated by the caller (if it wants to) based on the return value of this method - bool is_quorum_met(const quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal); //check if quorum has been met over a proposal + bool is_quorum_met(const quorum_certificate& qc, const hs_proposal_message& proposal); //check if quorum has been met over a proposal hs_proposal_message new_proposal_candidate(const block_id_type& block_id, uint8_t phase_counter); //create new proposal message hs_new_block_message new_block_candidate(const block_id_type& block_id); //create new block message @@ -147,7 +147,7 @@ namespace eosio::hotstuff { void process_new_view(const hs_new_view_message& msg); //handles new view void process_new_block(const hs_new_block_message& msg); //handles new block - hs_vote_message sign_proposal(const hs_proposal_message& proposal, name finalizer); //sign proposal + hs_vote_message sign_proposal(const hs_proposal_message& proposal, const fc::crypto::blslib::bls_private_key& finalizer_priv_key, const fc::crypto::blslib::bls_public_key& finalizer_pub_key); bool extends(const fc::sha256& descendant, const fc::sha256& ancestor); //verify that a proposal descends from another @@ -169,15 +169,6 @@ namespace eosio::hotstuff { void gc_proposals(uint64_t cutoff); //garbage collection of old proposals -#warning remove. bls12-381 key used for testing purposes - //todo : remove. bls12-381 key used for testing purposes - std::vector _seed = - { 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, - 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, - 12, 62, 89, 110, 182, 9, 44, 20, 254, 22 }; - - fc::crypto::blslib::bls_private_key _private_key = fc::crypto::blslib::bls_private_key(_seed); - enum msg_type { new_view = 1, new_block = 2, @@ -195,11 +186,11 @@ namespace eosio::hotstuff { quorum_certificate _high_qc; quorum_certificate _current_qc; uint32_t _v_height = 0; - eosio::chain::extended_schedule _schedule; + //eosio::chain::extended_schedule _schedule; base_pacemaker* _pacemaker = nullptr; std::set _my_producers; chain::bls_key_map_t _my_finalizer_keys; - name _id; + std::string _id; mutable std::atomic _state_version = 1; diff --git a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp index 567eb44465..3088b7642f 100644 --- a/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp +++ b/libraries/hotstuff/include/eosio/hotstuff/test_pacemaker.hpp @@ -9,9 +9,9 @@ namespace eosio { namespace hotstuff { //class-specific functions - bool is_qc_chain_active(const name & qcc_name) { return _qcc_deactivated.find(qcc_name) == _qcc_deactivated.end(); } + bool is_qc_chain_active(const name& qcc_name) { return _qcc_deactivated.find(qcc_name) == _qcc_deactivated.end(); } - using hotstuff_message = std::pair>; + using hotstuff_message = std::pair>; void set_proposer(name proposer); @@ -19,7 +19,7 @@ namespace eosio { namespace hotstuff { void set_next_leader(name next_leader); - void set_finalizers(std::vector finalizers); + void set_finalizer_keys(std::vector finalizers); void set_current_block_id(block_id_type id); @@ -41,26 +41,26 @@ namespace eosio { namespace hotstuff { void beat(); - void on_hs_vote_msg(const hs_vote_message & msg, name id); //confirmation msg event handler - void on_hs_proposal_msg(const hs_proposal_message & msg, name id); //consensus msg event handler - void on_hs_new_view_msg(const hs_new_view_message & msg, name id); //new view msg event handler - void on_hs_new_block_msg(const hs_new_block_message & msg, name id); //new block msg event handler + void on_hs_vote_msg(const hs_vote_message & msg, const std::string& id); //confirmation msg event handler + void on_hs_proposal_msg(const hs_proposal_message & msg, const std::string& id); //consensus msg event handler + void on_hs_new_view_msg(const hs_new_view_message & msg, const std::string& id); //new view msg event handler + void on_hs_new_block_msg(const hs_new_block_message & msg, const std::string& id); //new block msg event handler //base_pacemaker interface functions name get_proposer(); name get_leader(); name get_next_leader(); - std::vector get_finalizers(); + std::vector get_finalizer_keys(); block_id_type get_current_block_id(); uint32_t get_quorum_threshold(); - void send_hs_proposal_msg(const hs_proposal_message & msg, name id); - void send_hs_vote_msg(const hs_vote_message & msg, name id); - void send_hs_new_block_msg(const hs_new_block_message & msg, name id); - void send_hs_new_view_msg(const hs_new_view_message & msg, name id); + void send_hs_proposal_msg(const hs_proposal_message & msg, const std::string& id); + void send_hs_vote_msg(const hs_vote_message & msg, const std::string& id); + void send_hs_new_block_msg(const hs_new_block_message & msg, const std::string& id); + void send_hs_new_view_msg(const hs_new_view_message & msg, const std::string& id); std::vector _pending_message_queue; @@ -78,11 +78,10 @@ namespace eosio { namespace hotstuff { name _leader; name _next_leader; - std::vector _finalizers; + std::vector _finalizer_keys; block_id_type _current_block_id; - std::vector _unique_replicas; #warning calculate from schedule uint32_t _quorum_threshold = 15; //todo : calculate from schedule }; diff --git a/libraries/hotstuff/qc_chain.cpp b/libraries/hotstuff/qc_chain.cpp index e62381fb0e..12f68675c9 100644 --- a/libraries/hotstuff/qc_chain.cpp +++ b/libraries/hotstuff/qc_chain.cpp @@ -64,7 +64,6 @@ namespace eosio::hotstuff { fs.v_height = _v_height; fs.high_qc = _high_qc.to_msg(); fs.current_qc = _current_qc.to_msg(); - fs.schedule = _schedule; #ifdef QC_CHAIN_SIMPLE_PROPOSAL_STORE ps_height_iterator psh_it = _proposal_stores_by_height.begin(); while (psh_it != _proposal_stores_by_height.end()) { @@ -91,23 +90,25 @@ namespace eosio::hotstuff { return finalizers.count(); // the number of bits in this bitset that are set. } - hs_bitset qc_chain::update_bitset(const hs_bitset& finalizer_set, name finalizer ) { + hs_bitset qc_chain::update_bitset(const hs_bitset& finalizer_set, fc::crypto::blslib::bls_public_key finalizer_key ) { hs_bitset b(finalizer_set ); - vector finalizers = _pacemaker->get_finalizers(); - for (size_t i = 0; i < finalizers.size();i++) { - if (finalizers[i] == finalizer) { + + vector finalizer_keys = _pacemaker->get_finalizer_keys(); + + for (size_t i = 0; i < finalizer_keys.size();i++) { + if (finalizer_keys[i] == finalizer_key) { b.set(i); fc_tlog(_logger, " === finalizer found ${finalizer} new value : ${value}", - ("finalizer", finalizer)("value", [&](){ std::string r; boost::to_string(b, r); return r; }())); + ("finalizer_keys", finalizer_keys)("value", [&](){ std::string r; boost::to_string(b, r); return r; }())); return b; } } - fc_tlog(_logger, " *** finalizer not found ${finalizer}", - ("finalizer", finalizer)); - throw std::runtime_error("qc_chain internal error: finalizer not found"); + fc_tlog(_logger, " *** finalizer_key not found ${finalizer_key}", + ("finalizer_key", finalizer_key)); + throw std::runtime_error("qc_chain internal error: finalizer_key not found"); } digest_type qc_chain::get_digest_to_sign(const block_id_type& block_id, uint8_t phase_counter, const fc::sha256& final_on_qc){ @@ -182,8 +183,7 @@ namespace eosio::hotstuff { return b; } - bool qc_chain::evaluate_quorum(const extended_schedule& es, const hs_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal) { - + bool qc_chain::evaluate_quorum(const hs_bitset& finalizers, const fc::crypto::blslib::bls_signature& agg_sig, const hs_proposal_message& proposal) { if (positive_bits_count(finalizers) < _pacemaker->get_quorum_threshold()){ return false; @@ -191,26 +191,20 @@ namespace eosio::hotstuff { fc::crypto::blslib::bls_public_key agg_key; + std::vector pks =_pacemaker->get_finalizer_keys(); + bool first = true; for (hs_bitset::size_type i = 0; i < finalizers.size(); ++i) { if (finalizers[i]){ //adding finalizer's key to the aggregate pub key if (first) { first = false; - agg_key = _private_key.get_public_key(); + agg_key = pks[i]; } else { - agg_key = fc::crypto::blslib::aggregate({agg_key, _private_key.get_public_key()}); + agg_key = fc::crypto::blslib::aggregate({agg_key, pks[i]}); } } } -#warning fix todo - // **************************************************************************************************** - // FIXME/TODO: I removed this since it doesn't seem to be doing anything at the moment - // **************************************************************************************************** - // - //fc::crypto::blslib::bls_signature justification_agg_sig; - // - //if (proposal.justify.proposal_id != NULL_PROPOSAL_ID) justification_agg_sig = proposal.justify.active_agg_sig; digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); @@ -221,7 +215,7 @@ namespace eosio::hotstuff { return ok; } - bool qc_chain::is_quorum_met(const quorum_certificate& qc, const extended_schedule& schedule, const hs_proposal_message& proposal) { + bool qc_chain::is_quorum_met(const quorum_certificate& qc, const hs_proposal_message& proposal) { if (qc.is_quorum_met()) { return true; //skip evaluation if we've already verified quorum was met @@ -230,12 +224,13 @@ namespace eosio::hotstuff { fc_tlog(_logger, " === qc : ${qc}", ("qc", qc.to_msg())); // If the caller wants to update the quorum_met flag on its "qc" object, it will have to do so // based on the return value of this method, since "qc" here is const. - return evaluate_quorum(schedule, qc.get_active_finalizers(), qc.get_active_agg_sig(), proposal); + return evaluate_quorum(qc.get_active_finalizers(), qc.get_active_agg_sig(), proposal); } } - qc_chain::qc_chain(name id, base_pacemaker* pacemaker, + qc_chain::qc_chain(std::string id, + base_pacemaker* pacemaker, std::set my_producers, bls_key_map_t finalizer_keys, fc::logger& logger) @@ -266,34 +261,31 @@ namespace eosio::hotstuff { } bool qc_chain::am_i_finalizer(){ - std::vector finalizers = _pacemaker->get_finalizers(); - auto mf_itr = _my_producers.begin(); - while(mf_itr!=_my_producers.end()){ - name n = *mf_itr; - auto prod_itr = std::find_if(finalizers.begin(), finalizers.end(), [&](const auto& f){ return f == n; }); - if (prod_itr!=finalizers.end()) return true; - mf_itr++; + std::vector finalizers = _pacemaker->get_finalizer_keys(); + auto mfk_itr = _my_finalizer_keys.begin(); + while(mfk_itr!=_my_finalizer_keys.end()){ + auto fin_itr = std::find(finalizers.begin(), finalizers.end(), mfk_itr->first); + if (fin_itr!=finalizers.end()) return true; + mfk_itr++; } return false; } - hs_vote_message qc_chain::sign_proposal(const hs_proposal_message & proposal, name finalizer){ + hs_vote_message qc_chain::sign_proposal(const hs_proposal_message& proposal, const fc::crypto::blslib::bls_private_key& finalizer_priv_key, const fc::crypto::blslib::bls_public_key& finalizer_pub_key){ _v_height = proposal.get_height(); digest_type digest = get_digest_to_sign(proposal.block_id, proposal.phase_counter, proposal.final_on_qc); std::vector h = std::vector(digest.data(), digest.data() + 32); -#warning use appropriate private key for each producer - fc::crypto::blslib::bls_signature sig = _private_key.sign(h); //FIXME/TODO: use appropriate private key for each producer - hs_vote_message v_msg = {proposal.proposal_id, finalizer, sig}; + fc::crypto::blslib::bls_signature sig = finalizer_priv_key.sign(h); + + hs_vote_message v_msg = {proposal.proposal_id, finalizer_pub_key, sig}; return v_msg; } void qc_chain::process_proposal(const hs_proposal_message & proposal){ - //auto start = fc::time_point::now(); - if (!proposal.justify.proposal_id.empty()) { const hs_proposal_message *jp = get_proposal( proposal.justify.proposal_id ); @@ -307,7 +299,6 @@ namespace eosio::hotstuff { if (p != nullptr) { fc_elog(_logger, " *** ${id} proposal received twice : ${proposal_id}", ("id",_id)("proposal_id", proposal.proposal_id)); - if (p->justify.proposal_id != proposal.justify.proposal_id) { fc_elog(_logger, " *** ${id} two identical proposals (${proposal_id}) have different justifications : ${justify_1} vs ${justify_2}", @@ -338,7 +329,6 @@ namespace eosio::hotstuff { { const hs_proposal_message & existing_proposal = *hgt_itr; #endif - fc_elog(_logger, " *** ${id} received a different proposal at the same height (${block_num}, ${phase_counter})", ("id",_id) ("block_num", existing_proposal.block_num()) @@ -378,19 +368,18 @@ namespace eosio::hotstuff { std::vector msgs; if (signature_required){ + //iterate over all my finalizer keys and sign / broadcast for each that is in the schedule + std::vector finalizers = _pacemaker->get_finalizer_keys(); - //iterate over all my finalizers and sign / broadcast for each that is in the schedule - std::vector finalizers = _pacemaker->get_finalizers(); - - auto mf_itr = _my_producers.begin(); + auto mfk_itr = _my_finalizer_keys.begin(); - while(mf_itr!=_my_producers.end()){ + while(mfk_itr!=_my_finalizer_keys.end()){ - auto prod_itr = std::find(finalizers.begin(), finalizers.end(), *mf_itr); + auto fin_itr = std::find(finalizers.begin(), finalizers.end(), mfk_itr->first); - if (prod_itr!=finalizers.end()) { + if (fin_itr!=finalizers.end()) { - hs_vote_message v_msg = sign_proposal(proposal, *prod_itr); + hs_vote_message v_msg = sign_proposal(proposal, mfk_itr->second, mfk_itr->first); fc_tlog(_logger, " === ${id} signed proposal : block_num ${block_num} phase ${phase_counter} : proposal_id ${proposal_id}", ("id", _id) @@ -398,12 +387,11 @@ namespace eosio::hotstuff { ("phase_counter", proposal.phase_counter) ("proposal_id", proposal.proposal_id)); - //send_hs_vote_msg(v_msg); msgs.push_back(v_msg); }; - mf_itr++; + mfk_itr++; } } @@ -437,8 +425,8 @@ namespace eosio::hotstuff { if (!am_leader) return; - fc_tlog(_logger, " === Process vote from ${finalizer} : current bitset ${value}" , - ("finalizer", vote.finalizer)("value", _current_qc.get_active_finalizers_string())); + fc_tlog(_logger, " === Process vote from ${finalizer_key} : current bitset ${value}" , + ("finalizer_key", vote.finalizer_key)("value", _current_qc.get_active_finalizers_string())); // only leader need to take action on votes if (vote.proposal_id != _current_qc.get_proposal_id()) return; @@ -461,11 +449,10 @@ namespace eosio::hotstuff { _current_qc.set_active_agg_sig(fc::crypto::blslib::aggregate({_current_qc.get_active_agg_sig(), vote.sig })); else _current_qc.set_active_agg_sig(vote.sig); + fc_tlog(_logger, " === update bitset ${value} ${finalizer_key}", ("value", _current_qc.get_active_finalizers_string())("finalizer_key", vote.finalizer_key)); + _current_qc.set_active_finalizers(update_bitset(finalizer_set, vote.finalizer_key)); - fc_tlog(_logger, " === update bitset ${value} ${finalizer}", ("value", _current_qc.get_active_finalizers_string())("finalizer", vote.finalizer)); - _current_qc.set_active_finalizers(update_bitset(finalizer_set, vote.finalizer)); - - quorum_met = is_quorum_met(_current_qc, _schedule, *p); + quorum_met = is_quorum_met(_current_qc, *p); if (quorum_met){ @@ -688,7 +675,7 @@ namespace eosio::hotstuff { return false; if (new_high_qc_prop->get_height() > old_high_qc_prop->get_height() - && is_quorum_met(high_qc, _schedule, *new_high_qc_prop)) + && is_quorum_met(high_qc, *new_high_qc_prop)) { // "The caller does not need this updated on their high_qc structure" -- g //high_qc.quorum_met = true; diff --git a/libraries/hotstuff/test/test_hotstuff.cpp b/libraries/hotstuff/test/test_hotstuff.cpp index 997708fe91..0027799fcf 100644 --- a/libraries/hotstuff/test/test_hotstuff.cpp +++ b/libraries/hotstuff/test/test_hotstuff.cpp @@ -11,6 +11,7 @@ #include #include +#include #include using namespace eosio::hotstuff; @@ -35,6 +36,29 @@ std::vector unique_replicas { "bpp"_n, "bpq"_n, "bpr"_n, "bps"_n, "bpt"_n, "bpu"_n }; +std::vector unique_replica_keys { + "PVT_BLS_r4ZpChd87ooyzl6MIkw23k7PRX8xptp7TczLJHCIIW88h/hS", + "PVT_BLS_/l7xzXANaB+GrlTsbZEuTiSOiWTtpBoog+TZnirxUUSaAfCo", + "PVT_BLS_3FoY73Q/gED3ejyg8cvnGqHrMmx4cLKwh/e0sbcsCxpCeqn3", + "PVT_BLS_warwI76e+pPX9wLFZKPFagngeFM8bm6J8D5w0iiHpxW7PiId", + "PVT_BLS_iZFwiqdogOl9RNr1Hv1z+Rd6AwD9BIoxZcU1EPX+XFSFmm5p", + "PVT_BLS_Hmye7lyiCrdF54/nF/HRU0sY/Hrse1ls/yqojIUOVQsxXUIK", + "PVT_BLS_jglKDzpvyI+LFJ4xJG2MRylH9KiAEj//M9sgI+AM5mhLASBs", + "PVT_BLS_OWemmo0YkDNEYcMnbvAHI7qS6YIJTVBc+3LCAi9u8QmMe3V/", + "PVT_BLS_xYhEMbBy6Z4TYGha/qYaUwiwv4UVX9qNWf4ivRjAyCLCG7/G", + "PVT_BLS_ETZDiw3qd1Kpu3L5hH9fPKR4tg0meCkRUsRE2KpW8WP5SU2l", + "PVT_BLS_KuL3oMYpBrqmIMqoBIsA4UX1jYyXzn7et93J+m+ctk8FAY0I", + "PVT_BLS_bNz9W9QkxeREp966ntnUV4mN4dLOB4DNSghf2Y85o1YI+p7t", + "PVT_BLS_uP48z/V66g7wU7BwNN1xhNnZOyf3mv8yxGFT2eoIK3HLL5aw", + "PVT_BLS_/HIa+nJWSCgVNs6rZ3LUhqp1chRkxyaUxumvN3HSTAE4VIql", + "PVT_BLS_Aq4tqxG/sDEwGMZUa/Vhznc2i3B4wHNopGV3bJpTNW6FauCN", + "PVT_BLS_U3QCa0uwzeeK4w1hI2IvUzgF9+hk496LyODdvgYpUBmgZiwu", + "PVT_BLS_WyyJ26tRpjpzmwke/sGJr0YUIyB/zSNsbo/99PwDHh4pvo5V", + "PVT_BLS_t2xBqsJKO0RHQMvsIYHFpvuy+IkBrCVeZl1NxThKEwwvUbiP", + "PVT_BLS_94/Vo26YNQV1P7zWmkDnh02P0ZcPM5xQlLG3LiUCOUUgMpEi", + "PVT_BLS_uQ9ONJ/oJlj+yRIjE3tiLcoIXTMEuCwMuAFL1WUDY28N97gF", + "PVT_BLS_2qtUuz8cYjbu/shyUPxIwKrBMSSbvolv4iJJvykUMRFl4hGt"}; + fc::logger hotstuff_logger; class hotstuff_test_handler { @@ -42,7 +66,7 @@ class hotstuff_test_handler { std::vector>> _qc_chains; - void initialize_qc_chains(test_pacemaker& tpm, std::vector replicas){ + void initialize_qc_chains(test_pacemaker& tpm, std::vector replicas, std::vector replica_keys){ _qc_chains.clear(); @@ -52,14 +76,21 @@ class hotstuff_test_handler { //_qc_chains.reserve( 15 ); //_qc_chains.reserve( replicas.size() ); - for (name r : replicas) { - qc_chain *qcc_ptr = new qc_chain(r, &tpm, {r}, {}, hotstuff_logger); + //for (fc::crypto::blslib::bls_private_key r : replicas) { + for (size_t i = 0 ; i < replicas.size() ; i++){ + + fc::crypto::blslib::bls_private_key sk = fc::crypto::blslib::bls_private_key(replica_keys[i]); + + bls_key_map_t keys{{sk.get_public_key(), sk}}; + + qc_chain *qcc_ptr = new qc_chain(replica_keys[i].to_string(), &tpm, {replicas[i]}, keys, hotstuff_logger); std::shared_ptr qcc_shared_ptr(qcc_ptr); - _qc_chains.push_back( std::make_pair(r, qcc_shared_ptr) ); + _qc_chains.push_back( std::make_pair(replicas[i], qcc_shared_ptr) ); - tpm.register_qc_chain( r, qcc_shared_ptr ); + tpm.register_qc_chain(replicas[i], qcc_shared_ptr ); } + } void print_msgs(std::vector msgs ){ @@ -124,16 +155,16 @@ class hotstuff_test_handler { const hs_proposal_message *lock = fs.get_proposal( fs.b_lock ); const hs_proposal_message *exec = fs.get_proposal( fs.b_exec ); - if (leaf != nullptr) std::cout << " - " << bp.to_string() << " current _b_leaf is : " << fs.b_leaf.str() << " block_num : " << leaf->block_num() << ", phase : " << unsigned(leaf->phase_counter) << "\n"; + if (leaf != nullptr) std::cout << " - " << bp << " current _b_leaf is : " << fs.b_leaf.str() << " block_num : " << leaf->block_num() << ", phase : " << unsigned(leaf->phase_counter) << "\n"; else std::cout << " - No b_leaf value " << "\n"; - if (qc != nullptr) std::cout << " - " << bp.to_string() << " current high_qc is : " << fs.high_qc.proposal_id.str() << " block_num : " << qc->block_num() << ", phase : " << unsigned(qc->phase_counter) << "\n"; + if (qc != nullptr) std::cout << " - " << bp << " current high_qc is : " << fs.high_qc.proposal_id.str() << " block_num : " << qc->block_num() << ", phase : " << unsigned(qc->phase_counter) << "\n"; else std::cout << " - No high_qc value " << "\n"; - if (lock != nullptr) std::cout << " - " << bp.to_string() << " current _b_lock is : " << fs.b_lock.str() << " block_num : " << lock->block_num() << ", phase : " << unsigned(lock->phase_counter) << "\n"; + if (lock != nullptr) std::cout << " - " << bp << " current _b_lock is : " << fs.b_lock.str() << " block_num : " << lock->block_num() << ", phase : " << unsigned(lock->phase_counter) << "\n"; else std::cout << " - No b_lock value " << "\n"; - if (exec != nullptr) std::cout << " - " << bp.to_string() << " current _b_exec is : " << fs.b_exec.str() << " block_num : " << exec->block_num() << ", phase : " << unsigned(exec->phase_counter) << "\n"; + if (exec != nullptr) std::cout << " - " << bp << " current _b_exec is : " << fs.b_exec.str() << " block_num : " << exec->block_num() << ", phase : " << unsigned(exec->phase_counter) << "\n"; else std::cout << " - No b_exec value " << "\n"; std::cout << "\n"; @@ -181,12 +212,26 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, unique_replicas); + std::vector sks; + std::vector pks; + + + for (auto urk : unique_replica_keys){ + + fc::crypto::blslib::bls_private_key sk = fc::crypto::blslib::bls_private_key(urk); + fc::crypto::blslib::bls_public_key pk = sk.get_public_key(); + + sks.push_back(sk); + pks.push_back(pk); + } + + + ht.initialize_qc_chains(tpm, unique_replicas, sks); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); + tpm.set_finalizer_keys(pks); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); finalizer_state fs_bpa; @@ -195,7 +240,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { finalizer_state fs_bpb; qcc_bpb->second->get_state(fs_bpb); - ht.print_bp_state("bpa"_n, ""); + //ht.print_bp_state("bpa"_n, ""); tpm.set_current_block_id(ids[0]); //first block @@ -203,7 +248,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { tpm.dispatch(""); //send proposal to replicas (prepare on first block) - ht.print_bp_state("bpa"_n, ""); + //ht.print_bp_state("bpa"_n, ""); qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); @@ -215,12 +260,16 @@ BOOST_AUTO_TEST_CASE(hotstuff_1) try { tpm.dispatch(""); //send proposal to replicas (precommit on first block) + //ht.print_bp_state("bpa"_n, ""); + qcc_bpa->second->get_state(fs_bpa); BOOST_CHECK_EQUAL(fs_bpa.b_leaf.str(), std::string("4b43fb144a8b5e874777f61f3b37d7a8b06c33fbc48db464ce0e8788ff4edb4f")); BOOST_CHECK_EQUAL(fs_bpa.high_qc.proposal_id.str(), std::string("a252070cd26d3b231ab2443b9ba97f57fc72e50cca04a020952e45bc7e2d27a8")); BOOST_CHECK_EQUAL(fs_bpa.b_lock.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); BOOST_CHECK_EQUAL(fs_bpa.b_exec.str(), std::string("0000000000000000000000000000000000000000000000000000000000000000")); + + tpm.dispatch(""); //propagating votes on new proposal (precommitQC on first block) tpm.dispatch(""); //send proposal to replicas (commit on first block) @@ -311,12 +360,26 @@ BOOST_AUTO_TEST_CASE(hotstuff_2) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, unique_replicas); + std::vector sks; + std::vector pks; + + + for (auto urk : unique_replica_keys){ + + fc::crypto::blslib::bls_private_key sk = fc::crypto::blslib::bls_private_key(urk); + fc::crypto::blslib::bls_public_key pk = sk.get_public_key(); + + sks.push_back(sk); + pks.push_back(pk); + } + + + ht.initialize_qc_chains(tpm, unique_replicas, sks); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); + tpm.set_finalizer_keys(pks); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); finalizer_state fs_bpa; @@ -409,12 +472,25 @@ BOOST_AUTO_TEST_CASE(hotstuff_3) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, unique_replicas); + std::vector sks; + std::vector pks; + + + for (auto urk : unique_replica_keys){ + + fc::crypto::blslib::bls_private_key sk = fc::crypto::blslib::bls_private_key(urk); + fc::crypto::blslib::bls_public_key pk = sk.get_public_key(); + + sks.push_back(sk); + pks.push_back(pk); + } + + ht.initialize_qc_chains(tpm, unique_replicas, sks); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); + tpm.set_finalizer_keys(pks); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); finalizer_state fs_bpa; @@ -541,12 +617,26 @@ BOOST_AUTO_TEST_CASE(hotstuff_4) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, unique_replicas); + std::vector sks; + std::vector pks; + + + for (auto urk : unique_replica_keys){ + + fc::crypto::blslib::bls_private_key sk = fc::crypto::blslib::bls_private_key(urk); + fc::crypto::blslib::bls_public_key pk = sk.get_public_key(); + + sks.push_back(sk); + pks.push_back(pk); + } + + + ht.initialize_qc_chains(tpm, unique_replicas, sks); tpm.set_proposer("bpa"_n); tpm.set_leader("bpa"_n); tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); + tpm.set_finalizer_keys(pks); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); finalizer_state fs_bpa; @@ -720,6 +810,69 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { "bps"_n, "bpt"_n }; + std::vector honest_replica_set_keys_1 { + "PVT_BLS_/l7xzXANaB+GrlTsbZEuTiSOiWTtpBoog+TZnirxUUSaAfCo", + "PVT_BLS_iZFwiqdogOl9RNr1Hv1z+Rd6AwD9BIoxZcU1EPX+XFSFmm5p", + "PVT_BLS_OWemmo0YkDNEYcMnbvAHI7qS6YIJTVBc+3LCAi9u8QmMe3V/", + "PVT_BLS_KuL3oMYpBrqmIMqoBIsA4UX1jYyXzn7et93J+m+ctk8FAY0I", + "PVT_BLS_/HIa+nJWSCgVNs6rZ3LUhqp1chRkxyaUxumvN3HSTAE4VIql", + "PVT_BLS_WyyJ26tRpjpzmwke/sGJr0YUIyB/zSNsbo/99PwDHh4pvo5V"}; + + std::vector honest_replica_set_keys_2 { + "PVT_BLS_r4ZpChd87ooyzl6MIkw23k7PRX8xptp7TczLJHCIIW88h/hS", + "PVT_BLS_warwI76e+pPX9wLFZKPFagngeFM8bm6J8D5w0iiHpxW7PiId", + "PVT_BLS_jglKDzpvyI+LFJ4xJG2MRylH9KiAEj//M9sgI+AM5mhLASBs", + "PVT_BLS_ETZDiw3qd1Kpu3L5hH9fPKR4tg0meCkRUsRE2KpW8WP5SU2l", + "PVT_BLS_uP48z/V66g7wU7BwNN1xhNnZOyf3mv8yxGFT2eoIK3HLL5aw", + "PVT_BLS_U3QCa0uwzeeK4w1hI2IvUzgF9+hk496LyODdvgYpUBmgZiwu"}; + + std::vector byzantine_keys_set { + "PVT_BLS_3FoY73Q/gED3ejyg8cvnGqHrMmx4cLKwh/e0sbcsCxpCeqn3", + "PVT_BLS_Hmye7lyiCrdF54/nF/HRU0sY/Hrse1ls/yqojIUOVQsxXUIK", + "PVT_BLS_xYhEMbBy6Z4TYGha/qYaUwiwv4UVX9qNWf4ivRjAyCLCG7/G", + "PVT_BLS_bNz9W9QkxeREp966ntnUV4mN4dLOB4DNSghf2Y85o1YI+p7t", + "PVT_BLS_Aq4tqxG/sDEwGMZUa/Vhznc2i3B4wHNopGV3bJpTNW6FauCN", + "PVT_BLS_t2xBqsJKO0RHQMvsIYHFpvuy+IkBrCVeZl1NxThKEwwvUbiP", + "PVT_BLS_94/Vo26YNQV1P7zWmkDnh02P0ZcPM5xQlLG3LiUCOUUgMpEi", + "PVT_BLS_uQ9ONJ/oJlj+yRIjE3tiLcoIXTMEuCwMuAFL1WUDY28N97gF", + "PVT_BLS_2qtUuz8cYjbu/shyUPxIwKrBMSSbvolv4iJJvykUMRFl4hGt"}; + + std::vector sks1; + std::vector pks1; + + std::vector sks2; + std::vector pks2; + + std::vector sks3; + std::vector pks3; + + for (auto urk : honest_replica_set_keys_1){ + + fc::crypto::blslib::bls_private_key sk = fc::crypto::blslib::bls_private_key(urk); + fc::crypto::blslib::bls_public_key pk = sk.get_public_key(); + + sks1.push_back(sk); + pks1.push_back(pk); + } + + for (auto urk : honest_replica_set_keys_2){ + + fc::crypto::blslib::bls_private_key sk = fc::crypto::blslib::bls_private_key(urk); + fc::crypto::blslib::bls_public_key pk = sk.get_public_key(); + + sks2.push_back(sk); + pks2.push_back(pk); + } + + for (auto urk : byzantine_keys_set){ + + fc::crypto::blslib::bls_private_key sk = fc::crypto::blslib::bls_private_key(urk); + fc::crypto::blslib::bls_public_key pk = sk.get_public_key(); + + sks3.push_back(sk); + pks3.push_back(pk); + } + std::vector replica_set_1; std::vector replica_set_2; @@ -732,6 +885,30 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { replica_set_2.insert( replica_set_2.end(), honest_replica_set_2.begin(), honest_replica_set_2.end() ); replica_set_2.insert( replica_set_2.end(), byzantine_set.begin(), byzantine_set.end() ); + std::vector replica_pkeys_set_1; + std::vector replica_pkeys_set_2; + + std::vector replica_skeys_set_1; + std::vector replica_skeys_set_2; + + replica_pkeys_set_1.reserve( pks1.size() + pks3.size() ); + replica_pkeys_set_2.reserve( pks2.size() + pks3.size() ); + + replica_pkeys_set_1.insert( replica_pkeys_set_1.end(), pks1.begin(), pks1.end() ); + replica_pkeys_set_1.insert( replica_pkeys_set_1.end(), pks3.begin(), pks3.end() ); + + replica_pkeys_set_2.insert( replica_pkeys_set_2.end(), pks2.begin(), pks2.end() ); + replica_pkeys_set_2.insert( replica_pkeys_set_2.end(), pks3.begin(), pks3.end() ); + + replica_skeys_set_1.reserve( sks1.size() + sks3.size() ); + replica_skeys_set_2.reserve( sks2.size() + sks3.size() ); + + replica_skeys_set_1.insert( replica_skeys_set_1.end(), sks1.begin(), sks1.end() ); + replica_skeys_set_1.insert( replica_skeys_set_1.end(), sks3.begin(), sks3.end() ); + + replica_skeys_set_2.insert( replica_skeys_set_2.end(), sks2.begin(), sks2.end() ); + replica_skeys_set_2.insert( replica_skeys_set_2.end(), sks3.begin(), sks3.end() ); + //simulating a fork, where test_pacemaker tpm1; test_pacemaker tpm2; @@ -739,19 +916,19 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { hotstuff_test_handler ht1; hotstuff_test_handler ht2; - ht1.initialize_qc_chains(tpm1, replica_set_1); + ht1.initialize_qc_chains(tpm1, replica_set_1, replica_skeys_set_1); - ht2.initialize_qc_chains(tpm2, replica_set_2); + ht2.initialize_qc_chains(tpm2, replica_set_2, replica_skeys_set_2); tpm1.set_proposer("bpe"_n); //honest leader tpm1.set_leader("bpe"_n); tpm1.set_next_leader("bpe"_n); - tpm1.set_finalizers(replica_set_1); + tpm1.set_finalizer_keys(replica_pkeys_set_1); tpm2.set_proposer("bpf"_n); //byzantine leader tpm2.set_leader("bpf"_n); tpm2.set_next_leader("bpf"_n); - tpm2.set_finalizers(replica_set_2); + tpm2.set_finalizer_keys(replica_pkeys_set_2); auto qcc_bpe = std::find_if(ht1._qc_chains.begin(), ht1._qc_chains.end(), [&](const auto& q){ return q.first == "bpe"_n; }); finalizer_state fs_bpe; @@ -888,7 +1065,7 @@ BOOST_AUTO_TEST_CASE(hotstuff_5) try { } FC_LOG_AND_RETHROW(); -BOOST_AUTO_TEST_CASE(hotstuff_6) try { + BOOST_AUTO_TEST_CASE(hotstuff_6) try { //test simple separation between the (single) proposer and the leader; includes one leader rotation @@ -896,12 +1073,24 @@ BOOST_AUTO_TEST_CASE(hotstuff_6) try { hotstuff_test_handler ht; - ht.initialize_qc_chains(tpm, unique_replicas); + std::vector sks; + std::vector pks; + + for (auto urk : unique_replica_keys){ + + fc::crypto::blslib::bls_private_key sk = fc::crypto::blslib::bls_private_key(urk); + fc::crypto::blslib::bls_public_key pk = sk.get_public_key(); + + sks.push_back(sk); + pks.push_back(pk); + } + + ht.initialize_qc_chains(tpm, unique_replicas, sks); - tpm.set_proposer("bpg"_n); // can be any proposer that's not the leader for this test + tpm.set_proposer("bpg"_n); tpm.set_leader("bpa"_n); tpm.set_next_leader("bpa"_n); - tpm.set_finalizers(unique_replicas); + tpm.set_finalizer_keys(pks); auto qcc_bpa = std::find_if(ht._qc_chains.begin(), ht._qc_chains.end(), [&](const auto& q){ return q.first == "bpa"_n; }); finalizer_state fs_bpa; diff --git a/libraries/hotstuff/test/test_pacemaker.cpp b/libraries/hotstuff/test/test_pacemaker.cpp index de42e32ff1..62628e3989 100644 --- a/libraries/hotstuff/test/test_pacemaker.cpp +++ b/libraries/hotstuff/test/test_pacemaker.cpp @@ -15,8 +15,8 @@ namespace eosio::hotstuff { _next_leader = next_leader; }; - void test_pacemaker::set_finalizers(std::vector finalizers) { - _finalizers = finalizers; + void test_pacemaker::set_finalizer_keys(std::vector finalizer_keys) { + _finalizer_keys = finalizer_keys; }; void test_pacemaker::set_current_block_id(block_id_type id) { @@ -130,10 +130,10 @@ namespace eosio::hotstuff { return _next_leader; }; - std::vector test_pacemaker::get_finalizers() { - return _finalizers; + std::vector test_pacemaker::get_finalizer_keys() { + return _finalizer_keys; }; - + block_id_type test_pacemaker::get_current_block_id() { return _current_block_id; }; @@ -158,62 +158,66 @@ namespace eosio::hotstuff { _qcc_store.emplace( name, qcc_ptr ); }; - void test_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, name id) { + void test_pacemaker::send_hs_proposal_msg(const hs_proposal_message& msg, const std::string& id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, name id) { + void test_pacemaker::send_hs_vote_msg(const hs_vote_message& msg, const std::string& id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, name id) { + void test_pacemaker::send_hs_new_block_msg(const hs_new_block_message& msg, const std::string& id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, name id) { + void test_pacemaker::send_hs_new_view_msg(const hs_new_view_message& msg, const std::string& id) { _pending_message_queue.push_back(std::make_pair(id, msg)); }; - void test_pacemaker::on_hs_proposal_msg(const hs_proposal_message& msg, name id) { + void test_pacemaker::on_hs_proposal_msg(const hs_proposal_message& msg, const std::string& id) { auto qc_itr = _qcc_store.begin(); while (qc_itr != _qcc_store.end()){ const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ){ qcc_ptr->on_hs_proposal_msg(msg); + } qc_itr++; } } - void test_pacemaker::on_hs_vote_msg(const hs_vote_message& msg, name id) { + void test_pacemaker::on_hs_vote_msg(const hs_vote_message& msg, const std::string& id) { auto qc_itr = _qcc_store.begin(); while (qc_itr != _qcc_store.end()) { const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ){ qcc_ptr->on_hs_vote_msg(msg); + } qc_itr++; } } - void test_pacemaker::on_hs_new_block_msg(const hs_new_block_message& msg, name id) { + void test_pacemaker::on_hs_new_block_msg(const hs_new_block_message& msg, const std::string& id) { auto qc_itr = _qcc_store.begin(); while (qc_itr != _qcc_store.end()) { const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ){ qcc_ptr->on_hs_new_block_msg(msg); + } qc_itr++; } } - void test_pacemaker::on_hs_new_view_msg(const hs_new_view_message& msg, name id) { + void test_pacemaker::on_hs_new_view_msg(const hs_new_view_message& msg, const std::string& id) { auto qc_itr = _qcc_store.begin(); while (qc_itr != _qcc_store.end()){ const name & qcc_name = qc_itr->first; std::shared_ptr & qcc_ptr = qc_itr->second; - if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ) + if (qcc_ptr->get_id_i() != id && is_qc_chain_active(qcc_name) ){ qcc_ptr->on_hs_new_view_msg(msg); + } qc_itr++; } } diff --git a/libraries/libfc/test/test_bls.cpp b/libraries/libfc/test/test_bls.cpp index 3faa6d42e2..87ffd86b19 100644 --- a/libraries/libfc/test/test_bls.cpp +++ b/libraries/libfc/test/test_bls.cpp @@ -157,6 +157,31 @@ BOOST_AUTO_TEST_CASE(bls_agg_tree_verif) try { } FC_LOG_AND_RETHROW(); +// temp +BOOST_AUTO_TEST_CASE(bls_multi_key_gen) try { + + cout << "multi key" << "\n"; + + for (int i = 0; i < 21 ;i ++){ + + bls_private_key sk = bls_private_key::generate(); + bls_public_key pk = sk.get_public_key(); + + cout << sk.to_string() << "\n"; + + bls_signature signature = sk.sign(message_1); + + // Verify the signature + bool ok = verify(pk, message_1, signature); + + BOOST_CHECK_EQUAL(ok, true); + + } + + cout << "/multi key" << "\n"; + +} FC_LOG_AND_RETHROW(); + //test random key generation, signature + verification BOOST_AUTO_TEST_CASE(bls_key_gen) try {