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

Commit

Permalink
Merge pull request #259 from tendermint/abscissa/v0.1.0-pre.1
Browse files Browse the repository at this point in the history
Upgrade to Abscissa 0.1.0-pre.1
  • Loading branch information
tarcieri authored Jun 9, 2019
2 parents 4bf5224 + 3b3bd7b commit 20172d9
Show file tree
Hide file tree
Showing 57 changed files with 875 additions and 674 deletions.
619 changes: 382 additions & 237 deletions Cargo.lock

Large diffs are not rendered by default.

27 changes: 15 additions & 12 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,40 @@ members = [".", "tendermint-rs"]
[badges]
circle-ci = { repository = "tendermint/kms" }

[dependencies.abscissa]
version = "0.1.0-pre.1"
default-features = false
features = ["application", "signals", "secrets", "time"]

[dependencies]
abscissa = "0.0.6"
abscissa_derive = "0.0.2"
atomicwrites = "0.2"
byteorder = "1.2"
bytes = "0.4"
chrono = "0.4"
failure = "0.1"
failure_derive = "0.1"
gumdrop = "0.5"
hkdf = "0.7"
hmac = "0.7"
lazy_static = "1"
ledger-tendermint = { version = "0.4.0", optional = true }
log = "0.4"
prost-amino = "0.4.0"
prost-amino-derive = "0.4.0"
rand_os = "0.1"
serde = "1"
serde_derive = "1"
serde = { version = "1", features = ["serde_derive"] }
serde_json = "1"
sha2 = "0.8"
signal-hook = "0.1.7"
signatory = { version = "0.11.1", features = ["ed25519", "ecdsa"] }
signatory-dalek = "0.11"
signatory-secp256k1 = "0.11"
signatory = { version = "0.12", features = ["ed25519", "ecdsa"] }
signatory-dalek = "0.12"
signatory-secp256k1 = "0.12"
signatory-ledger-tm = { version = "0.12", optional = true }
subtle = "2"
subtle-encoding = { version = "0.3", features = ["bech32-preview"] }
tendermint = { version = "0.7", path = "tendermint-rs", features = ["amino-types", "secret-connection"] }
tiny-bip39 = "0.6"
wait-timeout = "0.2"
yubihsm = { version = "0.22", features = ["setup", "usb"], optional = true }
zeroize = "0.5"
yubihsm = { version = "0.25", features = ["setup", "usb"], optional = true }
zeroize = "0.9"

[dev-dependencies]
tempfile = "3"
Expand All @@ -55,7 +58,7 @@ rand = "0.6" # TODO: switch to the getrandom crate
[features]
default = []
softsign = []
ledgertm = ["ledger-tendermint"]
ledgertm = ["signatory-ledger-tm"]
yubihsm-mock = ["yubihsm/mockhsm"]

# Enable integer overflow checks in release builds for security reasons
Expand Down
96 changes: 87 additions & 9 deletions src/application.rs
Original file line number Diff line number Diff line change
@@ -1,25 +1,103 @@
//! Abscissa `Application` for the KMS
use abscissa::{self, Application, LoggingConfig};

use crate::{commands::KmsCommand, config::KmsConfig};
use abscissa::{application, Application, FrameworkError, LoggingConfig, StandardPaths};
use lazy_static::lazy_static;

lazy_static! {
/// Application state
pub static ref APPLICATION: application::Lock<KmsApplication> = application::Lock::default();
}

/// Obtain a read-only (multi-reader) lock on the application state.
///
/// Panics if the application state has not been initialized.
pub fn app_reader() -> application::lock::Reader<KmsApplication> {
APPLICATION.read()
}

/// Obtain an exclusive mutable lock on the application state.
pub fn app_writer() -> application::lock::Writer<KmsApplication> {
APPLICATION.write()
}

/// Obtain a read-only (multi-reader) lock on the application configuration.
///
/// Panics if the application configuration has not been loaded.
pub fn app_config() -> abscissa::config::Reader<KmsApplication> {
abscissa::config::Reader::new(&APPLICATION)
}

/// The `tmkms` application
#[derive(Debug)]
pub struct KmsApplication;
pub struct KmsApplication {
/// Application configuration.
config: Option<KmsConfig>,

/// Application state.
state: application::State<Self>,
}

impl KmsApplication {
/// Boot the application
// TODO: use the upstream implementation of this method
pub fn boot() {
abscissa::boot(KmsApplication)
impl Default for KmsApplication {
fn default() -> Self {
Self {
config: None,
state: application::State::default(),
}
}
}

impl Application for KmsApplication {
/// Entrypoint command for this application.
type Cmd = KmsCommand;
type Config = KmsConfig;

/// Application configuration.
type Cfg = KmsConfig;

/// Paths to resources within the application.
type Paths = StandardPaths;

/// Accessor for application configuration.
fn config(&self) -> Option<&KmsConfig> {
self.config.as_ref()
}

/// Borrow the application state immutably.
fn state(&self) -> &application::State<Self> {
&self.state
}

/// Borrow the application state mutably.
fn state_mut(&mut self) -> &mut application::State<Self> {
&mut self.state
}

/// Register all components used by this application.
///
/// If you would like to add additional components to your application
/// beyond the default ones provided by the framework, this is the place
/// to do so.
fn register_components(&mut self, command: &Self::Cmd) -> Result<(), FrameworkError> {
let components = self.framework_components(command)?;
self.state.components.register(components)
}

/// Post-configuration lifecycle callback.
///
/// Called regardless of whether config is loaded to indicate this is the
/// time in app lifecycle when configuration would be loaded if
/// possible.
fn after_config(&mut self, config: Option<Self::Cfg>) -> Result<(), FrameworkError> {
// Provide configuration to all component `after_config()` handlers
for component in self.state.components.iter_mut() {
component.after_config(config.as_ref())?;
}

self.config = config;
Ok(())
}

/// Get logging configuration from command-line options
fn logging_config(&self, command: &KmsCommand) -> LoggingConfig {
if command.verbose() {
LoggingConfig::verbose()
Expand Down
5 changes: 2 additions & 3 deletions src/bin/tmkms/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
//! Main entry point for the `tmkms` executable
extern crate tmkms;
use tmkms::KmsApplication;
use tmkms::application::APPLICATION;

/// Boot the `tmkms` application
fn main() {
KmsApplication::boot();
abscissa::boot(&APPLICATION);
}
6 changes: 3 additions & 3 deletions src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ pub use self::{
};
use crate::{
config::{chain::ChainConfig, KmsConfig},
error::KmsError,
error::Error,
keyring::{self, KeyRing},
};
use std::{path::PathBuf, sync::Mutex};
Expand All @@ -31,7 +31,7 @@ pub struct Chain {

impl Chain {
/// Attempt to create a `Chain` state from the given configuration
pub fn from_config(config: &ChainConfig) -> Result<Chain, KmsError> {
pub fn from_config(config: &ChainConfig) -> Result<Chain, Error> {
let state_file = match config.state_file {
Some(ref path) => path.to_owned(),
None => PathBuf::from(&format!("{}_priv_validator_state.json", config.id)),
Expand Down Expand Up @@ -62,7 +62,7 @@ impl Chain {
}

/// Initialize the chain registry from the configuration file
pub fn load_config(config: &KmsConfig) -> Result<(), KmsError> {
pub fn load_config(config: &KmsConfig) -> Result<(), Error> {
for config in &config.chain {
REGISTRY.register(Chain::from_config(config)?)?;
}
Expand Down
10 changes: 6 additions & 4 deletions src/chain/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
use super::{Chain, Guard, Id};
use crate::{
error::{KmsError, KmsErrorKind::*},
error::{Error, ErrorKind::*},
keyring,
};
use lazy_static::lazy_static;
use std::{collections::BTreeMap, sync::RwLock};

lazy_static! {
/// State of Tendermint blockchain networks
pub static ref REGISTRY: GlobalRegistry = GlobalRegistry::default();
}

Expand All @@ -21,7 +23,7 @@ impl Registry {
&mut self,
chain_id: &Id,
signer: keyring::ed25519::Signer,
) -> Result<(), KmsError> {
) -> Result<(), Error> {
// TODO(tarcieri):
let chain = self.0.get_mut(chain_id).ok_or_else(|| {
err!(
Expand All @@ -36,7 +38,7 @@ impl Registry {
}

/// Register a `Chain` with the registry
pub fn register_chain(&mut self, chain: Chain) -> Result<(), KmsError> {
pub fn register_chain(&mut self, chain: Chain) -> Result<(), Error> {
let chain_id = chain.id;

if self.0.insert(chain_id, chain).is_none() {
Expand Down Expand Up @@ -72,7 +74,7 @@ impl GlobalRegistry {
}

/// Register a chain with the registry
pub fn register(&self, chain: Chain) -> Result<(), KmsError> {
pub fn register(&self, chain: Chain) -> Result<(), Error> {
// TODO(tarcieri): better handle `PoisonError` here?
let mut registry = self.0.write().unwrap();
registry.register_chain(chain)
Expand Down
5 changes: 3 additions & 2 deletions src/chain/state/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
use crate::{
config::chain::HookConfig,
error::{KmsError, KmsErrorKind::HookError},
error::{Error, ErrorKind::HookError},
};
use serde::Deserialize;
use std::{process::Command, time::Duration};
use tendermint::block;
use wait_timeout::ChildExt;
Expand All @@ -16,7 +17,7 @@ const DEFAULT_TIMEOUT_SECS: u64 = 1;
pub const BLOCK_HEIGHT_SANITY_LIMIT: u64 = 9000;

/// Run the given hook command to obtain the last signing state
pub fn run(config: &HookConfig) -> Result<Output, KmsError> {
pub fn run(config: &HookConfig) -> Result<Output, Error> {
let mut child = Command::new(&config.cmd[0])
.args(&config.cmd[1..])
.spawn()?;
Expand Down
4 changes: 2 additions & 2 deletions src/chain/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ mod error;
pub mod hook;

pub use self::error::{StateError, StateErrorKind};
use crate::error::{KmsError, KmsErrorKind::*};
use crate::error::{Error, ErrorKind::*};
use atomicwrites::{AtomicFile, OverwriteBehavior};
use serde_json;
use std::{
Expand All @@ -25,7 +25,7 @@ pub struct State {

impl State {
/// Load the state from the given path
pub fn load_state<P>(path: P) -> Result<State, KmsError>
pub fn load_state<P>(path: P) -> Result<State, Error>
where
P: AsRef<Path>,
{
Expand Down
17 changes: 9 additions & 8 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use crate::{
config::ValidatorConfig,
error::{KmsError, KmsErrorKind},
error::{Error, ErrorKind},
keyring::SecretKeyEncoding,
session::Session,
};
Expand Down Expand Up @@ -120,7 +120,7 @@ fn tcp_session(
port: u16,
secret_key_path: &Path,
should_term: &Arc<AtomicBool>,
) -> Result<(), KmsError> {
) -> Result<(), Error> {
let secret_key = load_secret_connection_key(secret_key_path)?;

let node_public_key =
Expand All @@ -145,7 +145,7 @@ fn tcp_session(

session.request_loop(should_term)
})
.unwrap_or_else(|ref e| Err(KmsError::from_panic(e)))
.unwrap_or_else(|ref e| Err(Error::from_panic(e)))
}

/// Create a validator session over a Unix domain socket
Expand All @@ -154,7 +154,7 @@ fn unix_session(
max_height: Option<tendermint::block::Height>,
socket_path: &Path,
should_term: &Arc<AtomicBool>,
) -> Result<(), KmsError> {
) -> Result<(), Error> {
panic::catch_unwind(move || {
let mut session = Session::connect_unix(chain_id, max_height, socket_path)?;

Expand All @@ -166,16 +166,16 @@ fn unix_session(

session.request_loop(should_term)
})
.unwrap_or_else(|ref e| Err(KmsError::from_panic(e)))
.unwrap_or_else(|ref e| Err(Error::from_panic(e)))
}

/// Initialize KMS secret connection private key
fn load_secret_connection_key(path: &Path) -> Result<ed25519::Seed, KmsError> {
fn load_secret_connection_key(path: &Path) -> Result<ed25519::Seed, Error> {
if path.exists() {
Ok(
ed25519::Seed::decode_from_file(path, &SecretKeyEncoding::default()).map_err(|e| {
err!(
KmsErrorKind::ConfigError,
ErrorKind::ConfigError,
"error loading SecretConnection key from {}: {}",
path.display(),
e
Expand All @@ -184,7 +184,8 @@ fn load_secret_connection_key(path: &Path) -> Result<ed25519::Seed, KmsError> {
)
} else {
let seed = ed25519::Seed::generate();
seed.encode_to_file(path, &SecretKeyEncoding::default())?;
seed.encode_to_file(path, &SecretKeyEncoding::default())
.map_err(|_| Error::from(ErrorKind::IoError))?;
Ok(seed)
}
}
16 changes: 12 additions & 4 deletions src/commands/help.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
//! The `help` subcommand
use abscissa::{Callable, Command};
use abscissa::{Command, Runnable};

use super::KmsCommand;

/// The `help` subcommand
#[derive(Debug, Default, Options)]
pub struct HelpCommand {
/// Arguments to the `help` command
#[options(free)]
pub args: Vec<String>,
}

impl Callable for HelpCommand {
impl Runnable for HelpCommand {
/// Print help message
fn call(&self) {
KmsCommand::print_usage(self.args.as_slice());
fn run(&self) {
KmsCommand::print_usage(
&self
.args
.as_slice()
.iter()
.map(|arg| arg.as_ref())
.collect::<Vec<_>>(),
);
}
}
Loading

0 comments on commit 20172d9

Please sign in to comment.