Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IF: Add support to producer_plugin to load BLS finalizer keys #1602

Merged
merged 3 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions libraries/chain/fork_database.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ) {
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions libraries/chain/include/eosio/chain/hotstuff.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
namespace eosio::chain {

using hs_bitset = boost::dynamic_bitset<uint32_t>;
using bls_key_map_t = std::map<fc::crypto::blslib::bls_public_key, fc::crypto::blslib::bls_private_key>;

inline uint64_t compute_height(uint32_t block_height, uint32_t phase_counter) {
return (uint64_t{block_height} << 32) | phase_counter;
Expand Down
7 changes: 5 additions & 2 deletions libraries/hotstuff/chain_pacemaker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,12 @@ namespace eosio { namespace hotstuff {
#endif
//===============================================================================================

chain_pacemaker::chain_pacemaker(controller* chain, std::set<account_name> my_producers, fc::logger& logger)
chain_pacemaker::chain_pacemaker(controller* chain,
std::set<account_name> my_producers,
bls_key_map_t 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 ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ namespace eosio::hotstuff {

//class-specific functions

chain_pacemaker(controller* chain, std::set<account_name> my_producers, fc::logger& logger);
chain_pacemaker(controller* chain,
std::set<account_name> my_producers,
chain::bls_key_map_t finalizer_keys,
fc::logger& logger);
void register_bcast_function(std::function<void(const chain::hs_message&)> broadcast_hs_message);

void beat();
Expand Down
6 changes: 5 additions & 1 deletion libraries/hotstuff/include/eosio/hotstuff/qc_chain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,10 @@ namespace eosio::hotstuff {

qc_chain() = delete;

qc_chain(name id, base_pacemaker* pacemaker, std::set<name> my_producers, fc::logger& logger);
qc_chain(name id, base_pacemaker* pacemaker,
std::set<name> 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

Expand Down Expand Up @@ -195,6 +198,7 @@ namespace eosio::hotstuff {
eosio::chain::extended_schedule _schedule;
base_pacemaker* _pacemaker = nullptr;
std::set<name> _my_producers;
chain::bls_key_map_t _my_finalizer_keys;
name _id;

mutable std::atomic<uint64_t> _state_version = 1;
Expand Down
6 changes: 5 additions & 1 deletion libraries/hotstuff/qc_chain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,13 @@ namespace eosio::hotstuff {
}


qc_chain::qc_chain(name id, base_pacemaker* pacemaker, std::set<name> my_producers, fc::logger& logger)
qc_chain::qc_chain(name id, base_pacemaker* pacemaker,
std::set<name> my_producers,
bls_key_map_t finalizer_keys,
fc::logger& logger)
: _pacemaker(pacemaker),
_my_producers(std::move(my_producers)),
_my_finalizer_keys(std::move(finalizer_keys)),
_id(id),
_logger(logger)
{
Expand Down
2 changes: 1 addition & 1 deletion libraries/hotstuff/test/test_hotstuff.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<qc_chain> qcc_shared_ptr(qcc_ptr);

_qc_chains.push_back( std::make_pair(r, qcc_shared_ptr) );
Expand Down
4 changes: 2 additions & 2 deletions plugins/chain_plugin/chain_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<chain::account_name> my_producers) {
void chain_plugin::create_pacemaker(std::set<chain::account_name> 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), 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<void(const chain::hs_message&)> bcast_hs_message) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1031,7 +1031,7 @@ class chain_plugin : public plugin<chain_plugin> {
// Only call this after plugin_initialize()!
const controller& chain() const;

void create_pacemaker(std::set<chain::account_name> my_producers);
void create_pacemaker(std::set<chain::account_name> my_producers, chain::bls_key_map_t finalizer_keys);
void register_pacemaker_bcast_function(std::function<void(const chain::hs_message&)> bcast_hs_message);
void notify_hs_message( const chain::hs_message& msg );
void notify_hs_block_produced();
Expand Down
16 changes: 13 additions & 3 deletions plugins/producer_plugin/producer_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,7 @@ class producer_plugin_impl : public std::enable_shared_from_this<producer_plugin

using signature_provider_type = signature_provider_plugin::signature_provider_type;
std::map<chain::public_key_type, signature_provider_type> _signature_providers;
bls_key_map_t _finalizer_keys;
std::set<chain::account_name> _producers;
boost::asio::deadline_timer _timer;
block_timing_util::producer_watermarks _producer_watermarks;
Expand Down Expand Up @@ -1136,8 +1137,16 @@ void producer_plugin_impl::plugin_initialize(const boost::program_options::varia
const std::vector<std::string> key_spec_pairs = options["signature-provider"].as<std::vector<std::string>>();
for (const auto& key_spec_pair : key_spec_pairs) {
try {
const auto& [pubkey, provider] = app().get_plugin<signature_provider_plugin>().signature_provider_for_specification(key_spec_pair);
_signature_providers[pubkey] = provider;
const auto v = app().get_plugin<signature_provider_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<signature_provider_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) {
Expand Down Expand Up @@ -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); }));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include <eosio/chain/application.hpp>
#include <eosio/http_client_plugin/http_client_plugin.hpp>
#include <eosio/chain/types.hpp>
#include <fc/crypto/bls_private_key.hpp>
#include <fc/crypto/bls_public_key.hpp>

namespace eosio {

Expand All @@ -23,8 +25,12 @@ class signature_provider_plugin : public appbase::plugin<signature_provider_plug

using signature_provider_type = std::function<chain::signature_type(chain::digest_type)>;

std::pair<chain::public_key_type,signature_provider_type> 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<std::pair<chain::public_key_type,signature_provider_type>> 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<std::pair<fc::crypto::blslib::bls_public_key, fc::crypto::blslib::bls_private_key>> bls_public_key_for_specification(const std::string& spec) const;

private:
std::unique_ptr<class signature_provider_plugin_impl> my;
Expand Down
77 changes: 50 additions & 27 deletions plugins/signature_provider_plugin/signature_provider_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,38 @@ class signature_provider_plugin_impl {
return app().get_plugin<http_client_plugin>().get_client().post_sync(keosd_url, params, deadline).as<chain::signature_type>();
};
}

// public_key spec_type spec_data
std::tuple<std::string, std::string, std::string> 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<std::pair<chain::public_key_type,signature_provider_plugin::signature_provider_type>>
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()){}
Expand All @@ -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 <public-key>=<provider-spec>\n"
"Where:\n"
" <public-key> \tis a string form of a vaild EOSIO public key\n\n"
" <provider-spec> \tis a string in the form <provider-type>:<data>\n\n"
" <provider-type> \tis KEY, KEOSD, or SE\n\n"
" KEY:<data> \tis a string form of a valid EOSIO private key which maps to the provided public key\n\n"
" KEOSD:<data> \tis the URL where keosd is available and the approptiate wallet(s) are unlocked\n\n"
" <public-key> \tis a string form of a valid Antelope public key, including BLS finalizer key\n"
" <provider-spec> \tis a string in the form <provider-type>:<data>\n"
" <provider-type> \tis KEY, KEOSD, or SE\n"
" KEY:<data> \tis a string form of a valid Antelope private key which maps to the provided public key\n"
" KEOSD:<data> \tis the URL where keosd is available and the appropriate wallet(s) are unlocked\n\n"
;

}
Expand All @@ -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<int32_t>() );
}

std::pair<chain::public_key_type,signature_provider_plugin::signature_provider_type>

std::optional<std::pair<chain::public_key_type,signature_provider_plugin::signature_provider_type>>
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<std::pair<fc::crypto::blslib::bls_public_key, fc::crypto::blslib::bls_private_key>>
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
Loading