Skip to content

Commit

Permalink
[management][breaking] Add support for a distinct treasury root key
Browse files Browse the repository at this point in the history
Management now supports uploading a distinct treasury root key.

Also updated the layout to map to the reality that libra and treasury
root will only have a single owner.

Because of smoke tests reliance on treasury and libra root being the
same... management tests unfortunately do as well (see initialize in
storage_helper)
davidiw authored and bors-libra committed Sep 3, 2020

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent c197753 commit 5372bd2
Showing 10 changed files with 159 additions and 16 deletions.
1 change: 1 addition & 0 deletions config/global-constants/src/lib.rs
Original file line number Diff line number Diff line change
@@ -13,6 +13,7 @@ pub const CONSENSUS_KEY: &str = "consensus";
pub const EXECUTION_KEY: &str = "execution";
pub const FULLNODE_NETWORK_KEY: &str = "fullnode_network";
pub const LIBRA_ROOT_KEY: &str = "libra_root";
pub const TREASURY_COMPLIANCE_KEY: &str = "treasury_compliance";
pub const OPERATOR_ACCOUNT: &str = "operator_account";
pub const OPERATOR_KEY: &str = "operator";
pub const OWNER_ACCOUNT: &str = "owner_account";
27 changes: 24 additions & 3 deletions config/management/genesis/src/command.rs
Original file line number Diff line number Diff line change
@@ -24,6 +24,8 @@ pub enum Command {
SetLayout(crate::layout::SetLayout),
#[structopt(about = "Sets the validator operator chosen by the owner")]
SetOperator(crate::validator_operator::ValidatorOperator),
#[structopt(about = "Submits an Ed25519PublicKey for the treasury root")]
TreasuryComplianceKey(crate::key::TreasuryComplianceKey),
#[structopt(about = "Constructs and signs a ValidatorConfig")]
ValidatorConfig(crate::validator_config::ValidatorConfig),
#[structopt(about = "Verifies and prints the current configuration state")]
@@ -40,6 +42,7 @@ pub enum CommandName {
OwnerKey,
SetLayout,
SetOperator,
TreasuryComplianceKey,
ValidatorConfig,
Verify,
}
@@ -55,6 +58,7 @@ impl From<&Command> for CommandName {
Command::OwnerKey(_) => CommandName::OwnerKey,
Command::SetLayout(_) => CommandName::SetLayout,
Command::SetOperator(_) => CommandName::SetOperator,
Command::TreasuryComplianceKey(_) => CommandName::TreasuryComplianceKey,
Command::ValidatorConfig(_) => CommandName::ValidatorConfig,
Command::Verify(_) => CommandName::Verify,
}
@@ -72,6 +76,7 @@ impl std::fmt::Display for CommandName {
CommandName::OwnerKey => "owner-key",
CommandName::SetLayout => "set-layout",
CommandName::SetOperator => "set-operator",
CommandName::TreasuryComplianceKey => "treasury-compliance-key",
CommandName::ValidatorConfig => "validator-config",
CommandName::Verify => "verify",
};
@@ -92,6 +97,9 @@ impl Command {
Command::OwnerKey(_) => self.owner_key().unwrap().to_string(),
Command::SetLayout(_) => self.set_layout().unwrap().to_string(),
Command::SetOperator(_) => format!("{:?}", self.set_operator().unwrap()),
Command::TreasuryComplianceKey(_) => {
self.treasury_compliance_key().unwrap().to_string()
}
Command::ValidatorConfig(_) => format!("{:?}", self.validator_config().unwrap()),
Command::Verify(_) => self.verify().unwrap(),
}
@@ -133,6 +141,14 @@ impl Command {
execute_command!(self, Command::SetOperator, CommandName::SetOperator)
}

pub fn treasury_compliance_key(self) -> Result<Ed25519PublicKey, Error> {
execute_command!(
self,
Command::TreasuryComplianceKey,
CommandName::TreasuryComplianceKey
)
}

pub fn validator_config(self) -> Result<Transaction, Error> {
execute_command!(self, Command::ValidatorConfig, CommandName::ValidatorConfig)
}
@@ -189,7 +205,8 @@ pub mod tests {
let layout_text = "\
operators = [\"operator_alice_shared\", \"operator_bob_shared\", \"operator_carol_shared\"]\n\
owners = [\"alice_shared\", \"bob_shared\", \"carol_shared\"]\n\
libra_root = [\"dave_shared\"]\n\
libra_root = \"dave_shared\"\n\
treasury_compliance = \"dave_shared\"\n\
";

let temppath = libra_temppath::TempPath::new();
@@ -203,11 +220,14 @@ pub mod tests {
.set_layout(temppath.path().to_str().unwrap(), constants::COMMON_NS)
.unwrap();

// Step 2) Upload the libra root key:
// Step 2) Upload the root keys:
helper.initialize(dave_ns.into());
helper
.libra_root_key(dave_ns, &(dave_ns.to_string() + shared))
.unwrap();
helper
.treasury_compliance_key(dave_ns, &(dave_ns.to_string() + shared))
.unwrap();

// Step 3) Upload each owner key:
for ns in [alice_ns, bob_ns, carol_ns].iter() {
@@ -290,7 +310,8 @@ pub mod tests {
let layout_text = "\
operators = [\"alice\", \"bob\"]\n\
owners = [\"carol\"]\n\
libra_root = [\"dave\"]\n\
libra_root = \"dave\"\n\
treasury_compliance = \"other_dave\"\n\
";
file.write_all(&layout_text.to_string().into_bytes())
.unwrap();
12 changes: 8 additions & 4 deletions config/management/genesis/src/config_builder.rs
Original file line number Diff line number Diff line change
@@ -58,7 +58,8 @@ impl<T: AsRef<Path>> ValidatorBuilder<T> {
/// Association uploads the validator layout to shared storage.
fn create_layout(&self) {
let mut layout = Layout::default();
layout.libra_root = vec![LIBRA_ROOT_SHARED_NS.into()];
layout.libra_root = LIBRA_ROOT_SHARED_NS.into();
layout.treasury_compliance = LIBRA_ROOT_SHARED_NS.into();
layout.owners = (0..self.num_validators)
.map(|i| (i.to_string() + OWNER_SHARED_NS))
.collect();
@@ -71,12 +72,15 @@ impl<T: AsRef<Path>> ValidatorBuilder<T> {
common_storage.set(LAYOUT, layout_value).unwrap();
}

/// Association initializes its account and the libra root key.
fn create_libra_root(&self) {
/// Root initializes libra root and treasury root keys.
fn create_root(&self) {
self.storage_helper.initialize(LIBRA_ROOT_NS.into());
self.storage_helper
.libra_root_key(LIBRA_ROOT_NS, LIBRA_ROOT_SHARED_NS)
.unwrap();
self.storage_helper
.treasury_compliance_key(LIBRA_ROOT_NS, LIBRA_ROOT_SHARED_NS)
.unwrap();
}

/// Generate owner key locally and upload to shared storage.
@@ -191,7 +195,7 @@ impl<T: AsRef<Path>> ValidatorBuilder<T> {
impl<T: AsRef<Path>> BuildSwarm for ValidatorBuilder<T> {
fn build_swarm(&self) -> anyhow::Result<(Vec<NodeConfig>, Ed25519PrivateKey)> {
self.create_layout();
self.create_libra_root();
self.create_root();
let libra_root_key = self
.storage_helper
.storage(LIBRA_ROOT_NS.into())
12 changes: 10 additions & 2 deletions config/management/genesis/src/genesis.rs
Original file line number Diff line number Diff line change
@@ -41,12 +41,13 @@ impl Genesis {
pub fn execute(self) -> Result<Transaction, Error> {
let layout = self.layout()?;
let libra_root_key = self.libra_root_key(&layout)?;
let treasury_compliance_key = self.treasury_compliance_key(&layout)?;
let operator_assignments = self.operator_assignments(&layout)?;
let operator_registrations = self.operator_registrations(&layout)?;

let genesis = vm_genesis::encode_genesis_transaction(
libra_root_key.clone(),
libra_root_key,
treasury_compliance_key,
&operator_assignments,
&operator_registrations,
// TODO: swap back by 8/15
@@ -73,7 +74,7 @@ impl Genesis {
/// only supports a single libra root key.
pub fn libra_root_key(&self, layout: &Layout) -> Result<Ed25519PublicKey, Error> {
let config = self.config()?;
let storage = config.shared_backend_with_namespace(layout.libra_root[0].clone());
let storage = config.shared_backend_with_namespace(layout.libra_root.clone());
storage.ed25519_key(LIBRA_ROOT_KEY)
}

@@ -134,4 +135,11 @@ impl Genesis {

Ok(registrations)
}

/// Retrieves the treasury root key from the remote storage.
pub fn treasury_compliance_key(&self, layout: &Layout) -> Result<Ed25519PublicKey, Error> {
let config = self.config()?;
let storage = config.shared_backend_with_namespace(layout.libra_root.clone());
storage.ed25519_key(libra_global_constants::TREASURY_COMPLIANCE_KEY)
}
}
13 changes: 13 additions & 0 deletions config/management/genesis/src/key.rs
Original file line number Diff line number Diff line change
@@ -119,6 +119,19 @@ impl OwnerKey {
}
}

#[derive(Debug, StructOpt)]
pub struct TreasuryComplianceKey {
#[structopt(flatten)]
key: Key,
}

impl TreasuryComplianceKey {
pub fn execute(self) -> Result<Ed25519PublicKey, Error> {
self.key
.submit_key(libra_global_constants::TREASURY_COMPLIANCE_KEY, None)
}
}

#[cfg(test)]
mod tests {
use super::*;
9 changes: 6 additions & 3 deletions config/management/genesis/src/layout.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,8 @@ use structopt::StructOpt;
pub struct Layout {
pub operators: Vec<String>,
pub owners: Vec<String>,
pub libra_root: Vec<String>,
pub libra_root: String,
pub treasury_compliance: String,
}

impl Layout {
@@ -81,7 +82,8 @@ mod tests {
let contents = "\
operators = [\"alice\", \"bob\"]\n\
owners = [\"carol\"]\n\
libra_root = [\"dave\"]\n\
libra_root = \"dave\"\n\
treasury_compliance = \"other_dave\"\n\
";

let layout = Layout::parse(contents).unwrap();
@@ -90,6 +92,7 @@ mod tests {
vec!["alice".to_string(), "bob".to_string()]
);
assert_eq!(layout.owners, vec!["carol".to_string()]);
assert_eq!(layout.libra_root, vec!["dave".to_string()]);
assert_eq!(layout.libra_root, "dave");
assert_eq!(layout.treasury_compliance, "other_dave");
}
}
33 changes: 32 additions & 1 deletion config/management/genesis/src/storage_helper.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ use consensus_types::safety_data::SafetyData;
use libra_crypto::ed25519::Ed25519PublicKey;
use libra_global_constants::{
CONSENSUS_KEY, EXECUTION_KEY, FULLNODE_NETWORK_KEY, LIBRA_ROOT_KEY, OPERATOR_KEY, OWNER_KEY,
SAFETY_DATA, VALIDATOR_NETWORK_KEY, WAYPOINT,
SAFETY_DATA, TREASURY_COMPLIANCE_KEY, VALIDATOR_NETWORK_KEY, WAYPOINT,
};
use libra_management::{error::Error, secure_backend::DISK};
use libra_network_address::NetworkAddress;
@@ -47,6 +47,11 @@ impl StorageHelper {

// Initialize all keys in storage
storage.create_key(LIBRA_ROOT_KEY).unwrap();
// TODO(davidiw) use distinct keys in tests for treasury and libra root keys
let libra_root_key = storage.export_private_key(LIBRA_ROOT_KEY).unwrap();
storage
.import_private_key(TREASURY_COMPLIANCE_KEY, libra_root_key)
.unwrap();
storage.create_key(CONSENSUS_KEY).unwrap();
storage.create_key(EXECUTION_KEY).unwrap();
storage.create_key(FULLNODE_NETWORK_KEY).unwrap();
@@ -234,6 +239,32 @@ impl StorageHelper {
command.set_operator()
}

pub fn treasury_compliance_key(
&self,
validator_ns: &str,
shared_ns: &str,
) -> Result<Ed25519PublicKey, Error> {
let args = format!(
"
libra-genesis-tool
treasury-compliance-key
--validator-backend backend={backend};\
path={path};\
namespace={validator_ns}
--shared-backend backend={backend};\
path={path};\
namespace={shared_ns}
",
backend = DISK,
path = self.path_string(),
validator_ns = validator_ns,
shared_ns = shared_ns,
);

let command = Command::from_iter(args.split_whitespace());
command.treasury_compliance_key()
}

pub fn validator_config(
&self,
owner_name: &str,
2 changes: 1 addition & 1 deletion secure/storage/src/crypto_storage.rs
Original file line number Diff line number Diff line change
@@ -21,7 +21,7 @@ pub trait CryptoStorage {
/// not used correctly. As this is purely a testing API, there is no defined behavior for
/// importing a key for a given name if that name already exists. It only exists to allow
/// Libra to be run in test environments where a set of deterministic keys must be generated.
fn import_private_key(&mut self, _name: &str, _key: Ed25519PrivateKey) -> Result<(), Error>;
fn import_private_key(&mut self, name: &str, key: Ed25519PrivateKey) -> Result<(), Error>;

/// Returns the Ed25519 private key stored at 'name' and identified by 'version', which is the
/// corresponding public key. This may fail even if the 'named' key exists but the version is
31 changes: 29 additions & 2 deletions testsuite/cluster-test/src/cluster_builder.rs
Original file line number Diff line number Diff line change
@@ -26,7 +26,8 @@ use consensus_types::safety_data::SafetyData;
use libra_genesis_tool::layout::Layout;
use libra_global_constants::{
CONSENSUS_KEY, EXECUTION_KEY, FULLNODE_NETWORK_KEY, LIBRA_ROOT_KEY, OPERATOR_KEY, OWNER_KEY,
SAFETY_DATA, VALIDATOR_NETWORK_ADDRESS_KEYS, VALIDATOR_NETWORK_KEY, WAYPOINT,
SAFETY_DATA, TREASURY_COMPLIANCE_KEY, VALIDATOR_NETWORK_ADDRESS_KEYS, VALIDATOR_NETWORK_KEY,
WAYPOINT,
};
use libra_network_address::NetworkAddress;
use libra_secure_storage::{CryptoStorage, KVStorage, Storage, VaultStorage};
@@ -373,6 +374,21 @@ impl ClusterBuilder {
vault_storage.create_key(LIBRA_ROOT_KEY).map_err(|e| {
format_err!("Failed to create {}__{} : {}", pod_name, LIBRA_ROOT_KEY, e)
})?;
let key = vault_storage
.export_private_key(LIBRA_ROOT_KEY)
.map_err(|e| {
format_err!("Failed to export {}__{} : {}", pod_name, LIBRA_ROOT_KEY, e)
})?;
vault_storage
.import_private_key(TREASURY_COMPLIANCE_KEY, key)
.map_err(|e| {
format_err!(
"Failed to import {}__{} : {}",
pod_name,
TREASURY_COMPLIANCE_KEY,
e
)
})?;
}
let keys = vec![
OWNER_KEY,
@@ -421,7 +437,8 @@ impl ClusterBuilder {
let layout = Layout {
owners: owners.clone(),
operators: owners,
libra_root: vec![LIBRA_ROOT_NS.to_string()],
libra_root: LIBRA_ROOT_NS.to_string(),
treasury_compliance: LIBRA_ROOT_NS.to_string(),
};
let layout_path = "/tmp/layout.yaml";
write!(
@@ -459,6 +476,16 @@ impl ClusterBuilder {
)
.await
.map_err(|e| format_err!("Failed to libra_root_key : {}", e))?;
genesis_helper
.treasury_compliance_key(
VAULT_BACKEND,
format!("http://{}:{}", vault_nodes[0].internal_ip, VAULT_PORT).as_str(),
token_path,
LIBRA_ROOT_NS,
LIBRA_ROOT_NS,
)
.await
.map_err(|e| format_err!("Failed to libra_root_key : {}", e))?;

for (i, node) in vault_nodes.iter().enumerate() {
let pod_name = validator_pod_name(i as u32);
35 changes: 35 additions & 0 deletions testsuite/cluster-test/src/genesis_helper.rs
Original file line number Diff line number Diff line change
@@ -146,6 +146,41 @@ impl GenesisHelper {
.expect("tokio spawn_blocking runtime error")
}

pub async fn treasury_compliance_key(
&self,
validator_backend: &str,
server: &str,
token_path: &str,
validator_ns: &str,
shared_ns: &str,
) -> Result<Ed25519PublicKey, Error> {
let args = format!(
"
libra-genesis-tool
treasury-compliance-key
--validator-backend backend={validator_backend};\
server={server};\
token={token_path};\
namespace={validator_ns}
--shared-backend backend={backend};\
path={path};\
namespace={shared_ns}
",
backend = DISK,
validator_backend = validator_backend,
server = server,
token_path = token_path,
path = self.path,
validator_ns = validator_ns,
shared_ns = shared_ns,
);

let command = Command::from_iter(args.split_whitespace());
spawn_blocking(|| command.treasury_compliance_key())
.await
.expect("tokio spawn_blocking runtime error")
}

pub async fn validator_config(
&self,
owner_name: &str,

0 comments on commit 5372bd2

Please sign in to comment.