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

Save lp2p key #1301

Merged
merged 6 commits into from
Sep 1, 2022
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: 5 additions & 0 deletions core/application/app_configuration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ namespace kagome::application {
*/
virtual const std::optional<std::string> &nodeKeyFile() const = 0;

/**
* @return true if generated libp2p networking key should be saved
*/
virtual bool shouldSaveNodeKey() const = 0;

/**
* @return port for peer to peer interactions.
*/
Expand Down
4 changes: 4 additions & 0 deletions core/application/impl/app_configuration_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ namespace kagome::application {
AppConfigurationImpl::AppConfigurationImpl(log::Logger logger)
: logger_(std::move(logger)),
roles_(def_roles),
save_node_key_(false),
is_telemetry_enabled_(true),
p2p_port_(def_p2p_port),
max_blocks_in_response_(kAbsolutMaxBlocksInResponse),
Expand Down Expand Up @@ -676,6 +677,7 @@ namespace kagome::application {
("public-addr", po::value<std::vector<std::string>>()->multitoken(), "multiaddresses that other nodes use to connect to it")
("node-key", po::value<std::string>(), "the secret key to use for libp2p networking")
("node-key-file", po::value<std::string>(), "path to the secret key used for libp2p networking (raw binary or hex-encoded")
("save-node-key", po::bool_switch(), "save generated libp2p networking key, key will be reused on node restart")
("bootnodes", po::value<std::vector<std::string>>()->multitoken(), "multiaddresses of bootstrap nodes")
("port,p", po::value<uint16_t>(), "port for peer to peer interactions")
("rpc-host", po::value<std::string>(), "address for RPC over HTTP")
Expand Down Expand Up @@ -915,6 +917,8 @@ namespace kagome::application {
});
}

save_node_key_ = vm.count("save-node-key") != 0;

find_argument<uint16_t>(vm, "port", [&](uint16_t val) { p2p_port_ = val; });

auto parse_multiaddrs =
Expand Down
7 changes: 6 additions & 1 deletion core/application/impl/app_configuration_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@ namespace kagome::application {

const std::optional<std::string> &nodeKeyFile() const override {
return node_key_file_;
};
}

bool shouldSaveNodeKey() const override {
return save_node_key_;
}

const std::vector<libp2p::multi::Multiaddress> &listenAddresses()
const override {
Expand Down Expand Up @@ -269,6 +273,7 @@ namespace kagome::application {
network::Roles roles_;
std::optional<crypto::Ed25519PrivateKey> node_key_;
std::optional<std::string> node_key_file_;
bool save_node_key_;
std::vector<libp2p::multi::Multiaddress> listen_addresses_;
std::vector<libp2p::multi::Multiaddress> public_addresses_;
std::vector<libp2p::multi::Multiaddress> boot_nodes_;
Expand Down
3 changes: 1 addition & 2 deletions core/crypto/crypto_store/crypto_store_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -238,8 +238,7 @@ namespace kagome::crypto {
return ed25519KeyToLibp2pKeypair(kp);
}

libp2p::crypto::KeyPair CryptoStoreImpl::ed25519KeyToLibp2pKeypair(
const Ed25519Keypair &kp) const {
libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp) {
const auto &secret_key = kp.secret_key;
const auto &public_key = kp.public_key;
libp2p::crypto::PublicKey lp2p_public{
Expand Down
5 changes: 2 additions & 3 deletions core/crypto/crypto_store/crypto_store_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ namespace kagome::crypto {
WRONG_PUBLIC_KEY,
};

libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(const Ed25519Keypair &kp);

/// TODO(Harrm) Add policies to emit a warning when found a keypair
/// with incompatible type and algorithm (e. g. ed25519 BABE keypair,
/// whereas BABE has to be sr25519 only) or when trying to generate more
Expand Down Expand Up @@ -185,9 +187,6 @@ namespace kagome::crypto {
return it->second;
}

libp2p::crypto::KeyPair ed25519KeyToLibp2pKeypair(
const Ed25519Keypair &kp) const;

mutable std::unordered_map<KeyTypeId, KeyCache<EcdsaSuite>> ecdsa_caches_;
mutable std::unordered_map<KeyTypeId, KeyCache<Ed25519Suite>> ed_caches_;
mutable std::unordered_map<KeyTypeId, KeyCache<Sr25519Suite>> sr_caches_;
Expand Down
108 changes: 12 additions & 96 deletions core/injector/application_injector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
#include "crypto/vrf/vrf_provider_impl.hpp"
#include "host_api/impl/host_api_factory_impl.hpp"
#include "host_api/impl/host_api_impl.hpp"
#include "injector/get_peer_keypair.hpp"
#include "log/configurator.hpp"
#include "log/logger.hpp"
#include "metrics/impl/exposer_impl.hpp"
Expand Down Expand Up @@ -478,91 +479,6 @@ namespace {
return initialized.value();
}

const sptr<libp2p::crypto::KeyPair> &get_peer_keypair(
const application::AppConfiguration &app_config,
const crypto::Ed25519Provider &crypto_provider,
const crypto::CryptoStore &crypto_store) {
static auto initialized =
std::optional<sptr<libp2p::crypto::KeyPair>>(std::nullopt);

if (initialized) {
return initialized.value();
}

auto log = log::createLogger("Injector", "injector");

if (app_config.nodeKey()) {
log->info("Will use LibP2P keypair from config or 'node-key' CLI arg");

auto provided_keypair =
crypto_provider.generateKeypair(app_config.nodeKey().value());
BOOST_ASSERT(provided_keypair.secret_key == app_config.nodeKey().value());

auto &&pub = provided_keypair.public_key;
auto &&priv = provided_keypair.secret_key;

auto key_pair =
std::make_shared<libp2p::crypto::KeyPair>(libp2p::crypto::KeyPair{
.publicKey = {{.type = libp2p::crypto::Key::Type::Ed25519,
.data = {pub.begin(), pub.end()}}},
.privateKey = {{.type = libp2p::crypto::Key::Type::Ed25519,
.data = {priv.begin(), priv.end()}}}});

initialized.emplace(std::move(key_pair));
return initialized.value();
}

if (app_config.nodeKeyFile()) {
const auto &path = app_config.nodeKeyFile().value();
log->info(
"Will use LibP2P keypair from config or 'node-key-file' CLI arg");
auto key = crypto_store.loadLibp2pKeypair(path);
if (key.has_error()) {
log->error("Unable to load user provided key from {}. Error: {}",
path,
key.error().message());
} else {
auto key_pair =
std::make_shared<libp2p::crypto::KeyPair>(std::move(key.value()));
initialized.emplace(std::move(key_pair));
return initialized.value();
}
}

if (crypto_store.getLibp2pKeypair().has_value()) {
log->info(
"Will use LibP2P keypair from config or args (loading from base "
"path)");

auto stored_keypair = crypto_store.getLibp2pKeypair().value();

auto key_pair =
std::make_shared<libp2p::crypto::KeyPair>(std::move(stored_keypair));

initialized.emplace(std::move(key_pair));
return initialized.value();
}

log->warn(
"Can not obtain a libp2p keypair from crypto storage. "
"A unique one will be generated for the current session");

auto generated_keypair = crypto_provider.generateKeypair();

auto &&pub = generated_keypair.public_key;
auto &&priv = generated_keypair.secret_key;

auto key_pair =
std::make_shared<libp2p::crypto::KeyPair>(libp2p::crypto::KeyPair{
.publicKey = {{.type = libp2p::crypto::Key::Type::Ed25519,
.data = {pub.begin(), pub.end()}}},
.privateKey = {{.type = libp2p::crypto::Key::Type::Ed25519,
.data = {priv.begin(), priv.end()}}}});

initialized.emplace(std::move(key_pair));
return initialized.value();
}

sptr<libp2p::protocol::kademlia::Config> get_kademlia_config(
const application::ChainSpec &chain_spec,
std::chrono::seconds random_wak_interval) {
Expand Down Expand Up @@ -816,7 +732,7 @@ namespace {
template <typename... Ts>
auto makeWavmInjector(
application::AppConfiguration::RuntimeExecutionMethod method,
Ts &&... args) {
Ts &&...args) {
return di::make_injector(
di::bind<runtime::wavm::CompartmentWrapper>.template to(
[](const auto &injector) {
Expand Down Expand Up @@ -858,7 +774,7 @@ namespace {
template <typename... Ts>
auto makeBinaryenInjector(
application::AppConfiguration::RuntimeExecutionMethod method,
Ts &&... args) {
Ts &&...args) {
return di::make_injector(
di::bind<runtime::binaryen::RuntimeExternalInterface>.template to(
[](const auto &injector) {
Expand Down Expand Up @@ -932,7 +848,7 @@ namespace {
template <typename... Ts>
auto makeRuntimeInjector(
application::AppConfiguration::RuntimeExecutionMethod method,
Ts &&... args) {
Ts &&...args) {
return di::make_injector(
di::bind<runtime::TrieStorageProvider>.template to<runtime::TrieStorageProviderImpl>(),
di::bind<runtime::RuntimeUpgradeTrackerImpl>.template to(
Expand Down Expand Up @@ -1030,7 +946,7 @@ namespace {

template <typename... Ts>
auto makeApplicationInjector(const application::AppConfiguration &config,
Ts &&... args) {
Ts &&...args) {
// default values for configurations
api::RpcThreadPool::Configuration rpc_thread_pool_config{};
api::HttpSession::Configuration http_config{};
Expand Down Expand Up @@ -1106,8 +1022,9 @@ namespace {
auto &crypto_provider =
injector.template create<const crypto::Ed25519Provider &>();
auto &crypto_store =
injector.template create<const crypto::CryptoStore &>();
return get_peer_keypair(app_config, crypto_provider, crypto_store);
injector.template create<crypto::CryptoStore &>();
return injector::get_peer_keypair(
app_config, crypto_provider, crypto_store);
})[boost::di::override],

// bind io_context: 1 per injector
Expand Down Expand Up @@ -1350,11 +1267,10 @@ namespace {
if (config.roles().flags.authority) {
auto &crypto_provider =
injector.template create<const crypto::Ed25519Provider &>();
auto &crypto_store =
injector.template create<const crypto::CryptoStore &>();
auto &crypto_store = injector.template create<crypto::CryptoStore &>();

auto &local_pair =
get_peer_keypair(config, crypto_provider, crypto_store);
injector::get_peer_keypair(config, crypto_provider, crypto_store);

public_key = local_pair->publicKey;
} else {
Expand Down Expand Up @@ -1518,7 +1434,7 @@ namespace {

template <typename... Ts>
auto makeKagomeNodeInjector(const application::AppConfiguration &app_config,
Ts &&... args) {
Ts &&...args) {
using namespace boost; // NOLINT;

return di::make_injector(
Expand Down Expand Up @@ -1553,7 +1469,7 @@ namespace kagome::injector {
KagomeNodeInjector::KagomeNodeInjector(
const application::AppConfiguration &app_config)
: pimpl_{std::make_unique<KagomeNodeInjectorImpl>(
makeKagomeNodeInjector(app_config))} {}
makeKagomeNodeInjector(app_config))} {}

sptr<application::ChainSpec> KagomeNodeInjector::injectChainSpec() {
return pimpl_->injector_.create<sptr<application::ChainSpec>>();
Expand Down
102 changes: 102 additions & 0 deletions core/injector/get_peer_keypair.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright Soramitsu Co., Ltd. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef KAGOME_CORE_INJECTOR_GET_PEER_KEYPAIR_HPP
#define KAGOME_CORE_INJECTOR_GET_PEER_KEYPAIR_HPP

#include "application/app_configuration.hpp"
#include "common/outcome_throw.hpp"
#include "crypto/crypto_store/crypto_store_impl.hpp"
#include "crypto/ed25519_provider.hpp"

namespace kagome::injector {
inline const std::shared_ptr<libp2p::crypto::KeyPair> &get_peer_keypair(
const application::AppConfiguration &app_config,
const crypto::Ed25519Provider &crypto_provider,
crypto::CryptoStore &crypto_store) {
static auto initialized =
std::optional<std::shared_ptr<libp2p::crypto::KeyPair>>(std::nullopt);

if (initialized) {
return initialized.value();
}

auto log = log::createLogger("Injector", "injector");

if (app_config.nodeKey()) {
log->info("Will use LibP2P keypair from config or 'node-key' CLI arg");

auto provided_keypair =
crypto_provider.generateKeypair(app_config.nodeKey().value());
BOOST_ASSERT(provided_keypair.secret_key == app_config.nodeKey().value());

auto key_pair = std::make_shared<libp2p::crypto::KeyPair>(
crypto::ed25519KeyToLibp2pKeypair(provided_keypair));

initialized.emplace(std::move(key_pair));
return initialized.value();
}

if (app_config.nodeKeyFile()) {
const auto &path = app_config.nodeKeyFile().value();
log->info(
"Will use LibP2P keypair from config or 'node-key-file' CLI arg");
auto key = crypto_store.loadLibp2pKeypair(path);
if (key.has_error()) {
log->error("Unable to load user provided key from {}. Error: {}",
path,
key.error().message());
common::raise(key.error());
} else {
auto key_pair =
std::make_shared<libp2p::crypto::KeyPair>(std::move(key.value()));
initialized.emplace(std::move(key_pair));
return initialized.value();
}
}

if (crypto_store.getLibp2pKeypair().has_value()) {
log->info(
"Will use LibP2P keypair from config or args (loading from base "
"path)");

auto stored_keypair = crypto_store.getLibp2pKeypair().value();

auto key_pair =
std::make_shared<libp2p::crypto::KeyPair>(std::move(stored_keypair));

initialized.emplace(std::move(key_pair));
return initialized.value();
}

log->warn(
"Can not obtain a libp2p keypair from crypto storage. "
"A unique one will be generated");

kagome::crypto::Ed25519Keypair generated_keypair;
auto save = app_config.shouldSaveNodeKey();
if (save) {
auto res = crypto_store.generateEd25519KeypairOnDisk(
crypto::KnownKeyTypeId::KEY_TYPE_LP2P);
if (res.has_error()) {
log->warn("Can't save libp2p keypair: {}", res.error());
save = false;
} else {
generated_keypair = res.value();
}
}
if (not save) {
generated_keypair = crypto_provider.generateKeypair();
}

auto key_pair = std::make_shared<libp2p::crypto::KeyPair>(
crypto::ed25519KeyToLibp2pKeypair(generated_keypair));

initialized.emplace(std::move(key_pair));
return initialized.value();
}
} // namespace kagome::injector

#endif // KAGOME_CORE_INJECTOR_GET_PEER_KEYPAIR_HPP
2 changes: 2 additions & 0 deletions test/mock/core/application/app_configuration_mock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ namespace kagome::application {
(),
(const, override));

MOCK_METHOD(bool, shouldSaveNodeKey, (), (const, override));

MOCK_METHOD(const std::vector<libp2p::multi::Multiaddress> &,
listenAddresses,
(),
Expand Down