Skip to content
This repository has been archived by the owner on Jun 3, 2020. It is now read-only.

Commit

Permalink
[WIP] Chain registry
Browse files Browse the repository at this point in the history
  • Loading branch information
tony-iqlusion committed Mar 8, 2019
1 parent 3bfe6f1 commit 3268e4c
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 38 deletions.
9 changes: 9 additions & 0 deletions src/chain/chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
//! Information about particular Tendermint blockchain networks

use super::Id;

/// Information about a particular Tendermint blockchain network
pub struct Chain {
/// ID of a particular chain
pub id: Id,
}
19 changes: 19 additions & 0 deletions src/chain/guard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use super::{Chain, Id};
use std::{collections::BTreeMap, sync::RwLockReadGuard};

/// Wrapper for a `RwLockReadGuard<'static, BTreeMap<Id, Chain>>`, allowing access to
/// global information about particular Tendermint networks / "chains"
pub struct Guard<'lock>(RwLockReadGuard<'lock, BTreeMap<Id, Chain>>);

impl<'lock> From<RwLockReadGuard<'lock, BTreeMap<Id, Chain>>> for Guard<'lock> {
fn from(guard: RwLockReadGuard<'lock, BTreeMap<Id, Chain>>) -> Guard<'lock> {
Guard(guard)
}
}

impl<'lock> Guard<'lock> {
/// Get information about a particular chain ID (if registered)
pub fn chain(&self, chain_id: Id) -> Option<&Chain> {
self.0.get(&chain_id)
}
}
8 changes: 8 additions & 0 deletions src/chain/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
//! Tendermint "chains": metainformation about blockchain networks

mod chain;
mod guard;
mod registry;

pub use self::{chain::Chain, guard::Guard, registry::REGISTRY};
pub use tendermint::chain::Id;
42 changes: 42 additions & 0 deletions src/chain/registry.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//! Registry of information about known Tendermint blockchain networks

use super::{Chain, Guard, Id};
use crate::error::{KmsError, KmsErrorKind::ConfigError};
use std::{collections::BTreeMap, sync::RwLock};

lazy_static! {
pub static ref REGISTRY: Registry = Registry::default();
}

/// Registry of blockchain networks known to the KMS
// The `RwLock` is a bit of futureproofing as this data structure is for the
// most part "immutable". New chains should be registered at boot time.
// The only case in which this structure may change is in the event of
// runtime configuration reloading, so the `RwLock` is included as
// futureproofing for such a feature.
// See: <https://github.com/tendermint/kms/issues/183>
#[derive(Default)]
pub struct Registry(RwLock<BTreeMap<Id, Chain>>);

impl Registry {
/// Acquire a read-only (concurrent) lock to the internal chain registry
pub fn get(&self) -> Guard {
// TODO(tarcieri): better handle `PoisonError` here?
self.0.read().unwrap().into()
}

/// Register a chain with the registry
pub fn register(&self, chain: Chain) -> Result<(), KmsError> {
// TODO(tarcieri): better handle `PoisonError` here?
let mut chain_map = self.0.write().unwrap();

let chain_id = chain.id;

if chain_map.insert(chain_id, chain).is_none() {
Ok(())
} else {
// TODO(tarcieri): handle updating the set of registered chains
fail!(ConfigError, "chain ID already registered: {}", chain_id);
}
}
}
23 changes: 17 additions & 6 deletions src/commands/start.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
use abscissa::{Callable, GlobalConfig};
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::{thread, time};

use crate::{
chain::{self, Chain},
client::Client,
config::{KmsConfig, ValidatorConfig},
keyring::KeyRing,
};
use abscissa::{Callable, GlobalConfig};
use std::{
process,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
},
thread, time,
};

/// The `start` command
#[derive(Debug, Options)]
Expand Down Expand Up @@ -42,6 +46,13 @@ impl Callable for StartCommand {

let config = KmsConfig::get_global();

// TODO(tarcieri): configure chain registry from config
chain::REGISTRY
.register(Chain {
id: chain::Id::from("cosmoshub"),
})
.unwrap();

KeyRing::load_from_config(&config.providers).unwrap_or_else(|e| {
status_err!("couldn't load keyring: {}", e);
process::exit(1);
Expand Down
7 changes: 6 additions & 1 deletion src/config/provider/ledgertm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
//! Configuration for Ledger Tendermint signer

use crate::chain;

/// Ledger Tendermint signer configuration
#[derive(Clone, Deserialize, Debug)]
pub struct LedgerTendermintConfig {}
pub struct LedgerTendermintConfig {
/// Chains this signing key is authorized to be used from
pub chains: Vec<chain::Id>,
}
5 changes: 3 additions & 2 deletions src/config/provider/softsign.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
//! Configuration for software-backed signer (using ed25519-dalek)

use crate::chain;
use std::path::{Path, PathBuf};

/// Software signer configuration
#[derive(Clone, Deserialize, Debug)]
pub struct SoftSignConfig {
/// Identifier for this key
pub id: String,
/// Chains this signing key is authorized to be used from
pub chains: Vec<chain::Id>,

/// Path to a file containing a cryptographic key
// TODO: use `abscissa::Secret` to wrap this `PathBuf`
Expand Down
5 changes: 3 additions & 2 deletions src/config/provider/yubihsm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Configuration for the `YubiHSM` backend

use crate::chain;
use abscissa::{
secrets::{BorrowSecret, DebugSecret, Secret},
util::Zeroize,
Expand Down Expand Up @@ -111,8 +112,8 @@ impl Zeroize for Password {

#[derive(Clone, Debug, Deserialize)]
pub struct SigningKeyConfig {
/// Identifier for this key
pub id: String,
/// Chains this signing key is authorized to be used from
pub chains: Vec<chain::Id>,

/// Signing key ID
pub key: u16,
Expand Down
9 changes: 6 additions & 3 deletions src/keyring/ed25519/ledgertm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@ use signatory_ledger_tm::{self, Ed25519LedgerTmAppSigner};
use crate::{
config::provider::ledgertm::LedgerTendermintConfig,
error::{KmsError, KmsErrorKind::*},
keyring::{ed25519::Signer, KeyRing},
keyring::{ed25519::Signer, KeyRing, SigningProvider},
};

pub const LEDGER_TM_PROVIDER_LABEL: &str = "ledgertm";
pub const LEDGER_TM_ID: &str = "ledgertm";

/// Create Ledger Tendermint signer object from the given configuration
Expand All @@ -31,7 +30,11 @@ pub fn init(
let provider = Box::new(Ed25519LedgerTmAppSigner::connect()?);
let pk = provider.public_key()?;
// TODO: key_id shouldn't be a constant here (see LEDGER_TM_ID):
let signer = Signer::new(LEDGER_TM_PROVIDER_LABEL, LEDGER_TM_ID.to_string(), provider);
let signer = Signer::new(
SigningProvider::LedgerTm,
&ledgertm_configs.chains,
provider,
);
keyring.add(pk, signer)?;
Ok(())
}
37 changes: 25 additions & 12 deletions src/keyring/ed25519/signer.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,47 @@
use crate::error::{KmsError, KmsErrorKind::*};
use crate::{
chain,
error::{KmsError, KmsErrorKind::*},
keyring::SigningProvider,
};
use signatory::{self, ed25519::Signature, Signer as SignerTrait};

/// Wrapper for an Ed25519 signing provider (i.e. trait object)
pub struct Signer {
/// Name of the signature provider for this key
pub provider_name: &'static str,
/// Provider for this signer
provider: SigningProvider,

/// ID which identifies this key (should be unique-per-provider)
pub key_id: String,
/// Chains this key is authorized to be used from
chains: Vec<chain::Id>,

/// Signer trait object
provider: Box<dyn SignerTrait<Signature>>,
signer: Box<dyn SignerTrait<Signature>>,
}

impl Signer {
/// Create a new signer
pub fn new(
provider_name: &'static str,
key_id: String,
provider: Box<dyn SignerTrait<Signature>>,
provider: SigningProvider,
chains: &[chain::Id],
signer: Box<dyn SignerTrait<Signature>>,
) -> Self {
Self {
provider_name,
key_id,
provider,
chains: chains.to_vec(),
signer,
}
}

/// Get the provider for this signer
pub fn provider(&self) -> SigningProvider {
self.provider
}

/// Get the chains this signer is authorized to be used on
pub fn chains(&self) -> &[chain::Id] {
&self.chains
}

/// Sign the given message using this signer
#[inline]
pub fn sign(&self, msg: &[u8]) -> Result<Signature, KmsError> {
Ok(
signatory::sign(self.provider.as_ref(), msg)
Expand Down
8 changes: 2 additions & 6 deletions src/keyring/ed25519/softsign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@ use super::Signer;
use crate::{
config::provider::softsign::SoftSignConfig,
error::{KmsError, KmsErrorKind::*},
keyring::KeyRing,
keyring::{KeyRing, SigningProvider},
};

/// Label for ed25519-dalek provider
// TODO: use a non-string type for these, e.g. an enum
pub const DALEK_PROVIDER_LABEL: &str = "dalek";

/// Create software-backed Ed25519 signer objects from the given configuration
pub fn init(keyring: &mut KeyRing, configs: &[SoftSignConfig]) -> Result<(), KmsError> {
for config in configs {
Expand All @@ -33,7 +29,7 @@ pub fn init(keyring: &mut KeyRing, configs: &[SoftSignConfig]) -> Result<(), Kms

keyring.add(
provider.public_key()?,
Signer::new(DALEK_PROVIDER_LABEL, config.id.clone(), provider),
Signer::new(SigningProvider::SoftSign, &config.chains, provider),
)?;
}

Expand Down
8 changes: 2 additions & 6 deletions src/keyring/ed25519/yubihsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
use crate::{
config::provider::yubihsm::YubihsmConfig,
error::{KmsError, KmsErrorKind::*},
keyring::{ed25519::Signer, KeyRing},
keyring::{ed25519::Signer, KeyRing, SigningProvider},
};
use signatory::PublicKeyed;

/// Label for YubiHSM provider
// TODO: use a non-string type for these, e.g. an enum
pub const YUBIHSM_PROVIDER_LABEL: &str = "yubihsm";

/// Create hardware-backed YubiHSM signer objects from the given configuration
pub fn init(keyring: &mut KeyRing, yubihsm_configs: &[YubihsmConfig]) -> Result<(), KmsError> {
if yubihsm_configs.is_empty() {
Expand All @@ -32,7 +28,7 @@ pub fn init(keyring: &mut KeyRing, yubihsm_configs: &[YubihsmConfig]) -> Result<

keyring.add(
signer.public_key()?,
Signer::new(YUBIHSM_PROVIDER_LABEL, config.id.clone(), Box::new(signer)),
Signer::new(SigningProvider::Yubihsm, &config.chains, Box::new(signer)),
)?;
}

Expand Down
2 changes: 2 additions & 0 deletions src/keyring/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
//! Signing keyring. Presently specialized for Ed25519.

mod ed25519;
mod providers;

use self::ed25519::Signer;
pub use self::providers::SigningProvider;
use crate::{
config::provider::ProviderConfig,
error::{KmsError, KmsErrorKind::*},
Expand Down
32 changes: 32 additions & 0 deletions src/keyring/providers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::fmt::{self, Display};

/// Enumeration of signing key providers
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
pub enum SigningProvider {
/// YubiHSM provider
#[cfg(feature = "yubihsm")]
Yubihsm,

/// Ledger + Tendermint application
#[cfg(feature = "ledgertm")]
LedgerTm,

/// Software signer (not intended for production use)
#[cfg(feature = "softsign")]
SoftSign,
}

impl Display for SigningProvider {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
#[cfg(feature = "yubihsm")]
SigningProvider::Yubihsm => write!(f, "yubihsm"),

#[cfg(feature = "ledgertm")]
SigningProvider::LedgerTm => write!(f, "ledgertm"),

#[cfg(feature = "softsign")]
SigningProvider::SoftSign => write!(f, "softsign"),
}
}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extern crate serde_derive;
mod error;

mod application;
mod chain;
mod client;
mod commands;
mod config;
Expand Down

0 comments on commit 3268e4c

Please sign in to comment.