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

Commit

Permalink
Upgrade to Abscissa 0.1.0-pre.1
Browse files Browse the repository at this point in the history
I'm preparing another release of Abscissa, which provides the
application boilerplate / framework used by Tendermint KMS:

https://github.com/iqlusioninc/abscissa

This commit contains what is hopefully the minimum set of changes
required to upgrade to the new version.

Notably it removes all TODOs about boilerplate code that could
potentially be replaced by custom derive, as `abscissa_derive` now
provides that functionality.

It also incorporates global application state, and the application as
the owner of the configuration.
  • Loading branch information
tony-iqlusion committed Jun 5, 2019
1 parent ba31356 commit 4c48980
Show file tree
Hide file tree
Showing 46 changed files with 646 additions and 468 deletions.
499 changes: 307 additions & 192 deletions Cargo.lock

Large diffs are not rendered by default.

17 changes: 10 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,27 @@ 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"
Expand All @@ -45,8 +48,8 @@ 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.24", features = ["setup", "usb"], optional = true }
zeroize = "0.9"

[dev-dependencies]
tempfile = "3"
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);
}
2 changes: 2 additions & 0 deletions src/chain/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ use crate::{
error::{KmsError, KmsErrorKind::*},
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 Down
1 change: 1 addition & 0 deletions src/chain/state/hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
config::chain::HookConfig,
error::{KmsError, KmsErrorKind::HookError},
};
use serde::Deserialize;
use std::{process::Command, time::Duration};
use tendermint::block;
use wait_timeout::ChildExt;
Expand Down
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<_>>(),
);
}
}
6 changes: 3 additions & 3 deletions src/commands/keygen.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::keyring::SecretKeyEncoding;
use abscissa::Callable;
use abscissa::Runnable;
use signatory::{ed25519, Encode};
use std::{env, process};

Expand All @@ -10,9 +10,9 @@ pub struct KeygenCommand {
output_paths: Vec<String>,
}

impl Callable for KeygenCommand {
impl Runnable for KeygenCommand {
/// Generate an Ed25519 secret key for use with a software provider (i.e. ed25519-dalek)
fn call(&self) {
fn run(&self) {
if self.output_paths.len() != 1 {
eprintln!("Usage: {} keygen [PATH]", env::args().next().unwrap());
process::exit(2);
Expand Down
35 changes: 16 additions & 19 deletions src/commands/ledger/mod.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,21 @@
//! Subcommands of the `tmkms` command-line application

use crate::chain;
use crate::config::KmsConfig;
use abscissa::{Callable, GlobalConfig};
use crate::{chain, prelude::*};
use abscissa::{Command, Runnable};
use std::process;
use tendermint::amino_types::vote::{SignVoteRequest, Vote};
use tendermint::amino_types::{SignableMsg, SignedMsgType};
use tendermint::amino_types::{
vote::{SignVoteRequest, Vote},
SignableMsg, SignedMsgType,
};

#[derive(Debug, Options)]
/// `ledger` subcommand
#[derive(Command, Debug, Options, Runnable)]
pub enum LedgerCommand {
/// Initialize HRS values
#[options(help = "initialise the height/round/step")]
Initialise(InitCommand),
}

impl_command!(LedgerCommand);

impl Callable for LedgerCommand {
fn call(&self) {
match self {
LedgerCommand::Initialise(init) => init.call(),
}
}
}

impl LedgerCommand {
pub(super) fn config_path(&self) -> Option<&String> {
match self {
Expand All @@ -31,21 +24,25 @@ impl LedgerCommand {
}
}

/// `ledger init` subcommand
#[derive(Debug, Options)]
pub struct InitCommand {
/// config file path
#[options(short = "c", long = "config")]
pub config: Option<String>,

/// block height
#[options(short = "h", long = "height")]
pub height: Option<i64>,

/// block round
#[options(short = "r", long = "round")]
pub round: Option<i64>,
}

impl Callable for InitCommand {
fn call(&self) {
let config = KmsConfig::get_global();
impl Runnable for InitCommand {
fn run(&self) {
let config = app_config();

chain::load_config(&config).unwrap_or_else(|e| {
status_err!("error loading configuration: {}", e);
Expand Down
32 changes: 9 additions & 23 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,39 @@ pub use self::{
help::HelpCommand, keygen::KeygenCommand, start::StartCommand, version::VersionCommand,
};
use crate::config::{KmsConfig, CONFIG_ENV_VAR, CONFIG_FILE_NAME};
use abscissa::{Callable, LoadConfig};
use abscissa::{Command, Configurable, Runnable};
use std::{env, path::PathBuf};

/// Subcommands of the KMS command-line application
#[derive(Debug, Options)]
#[derive(Command, Debug, Options, Runnable)]
pub enum KmsCommand {
/// `help` subcommand
#[options(help = "show help for a command")]
Help(HelpCommand),

/// `keygen` subcommand
#[options(help = "generate a new software signing key")]
Keygen(KeygenCommand),

/// `start` subcommand
#[options(help = "start the KMS application")]
Start(StartCommand),

/// `version` subcommand
#[options(help = "display version information")]
Version(VersionCommand),

/// `yubihsm` subcommand
#[cfg(feature = "yubihsm")]
#[options(help = "subcommands for YubiHSM2")]
Yubihsm(YubihsmCommand),

/// `ledgertm` subcommand
#[cfg(feature = "ledgertm")]
#[options(help = "subcommands for Ledger")]
Ledger(LedgerCommand),
}

// TODO: refactor abscissa internally so this is all part of the proc macro
impl_command!(KmsCommand);

impl KmsCommand {
/// Are we configured for verbose logging?
pub fn verbose(&self) -> bool {
Expand All @@ -59,7 +62,7 @@ impl KmsCommand {
}
}

impl LoadConfig<KmsConfig> for KmsCommand {
impl Configurable<KmsConfig> for KmsCommand {
/// Get the path to the configuration file, either from selected subcommand
/// or the default
fn config_path(&self) -> Option<PathBuf> {
Expand All @@ -82,20 +85,3 @@ impl LoadConfig<KmsConfig> for KmsCommand {
Some(path)
}
}

// TODO: refactor abscissa internally so this is all part of the proc macro
impl Callable for KmsCommand {
/// Call the given command chosen via the CLI
fn call(&self) {
match self {
KmsCommand::Help(help) => help.call(),
KmsCommand::Keygen(keygen) => keygen.call(),
KmsCommand::Start(run) => run.call(),
KmsCommand::Version(version) => version.call(),
#[cfg(feature = "yubihsm")]
KmsCommand::Yubihsm(yubihsm) => yubihsm.call(),
#[cfg(feature = "ledgertm")]
KmsCommand::Ledger(ledger) => ledger.call(),
}
}
}
Loading

0 comments on commit 4c48980

Please sign in to comment.