From 14686f2652a5d5f6b665b9bef072353cf43f4d9e Mon Sep 17 00:00:00 2001 From: Svyatoslav Nikolsky Date: Fri, 24 Nov 2017 12:33:33 +0300 Subject: [PATCH] SecretStore: cli option to configure service contract --- parity/cli/mod.rs | 7 +++ parity/cli/tests/config.full.toml | 1 + parity/configuration.rs | 11 ++++- parity/secretstore.rs | 20 +++++++- secret_store/src/key_storage.rs | 1 + secret_store/src/lib.rs | 28 ++++++----- secret_store/src/listener/service_contract.rs | 48 ++++++++++++------- secret_store/src/types/all.rs | 11 +++++ 8 files changed, 94 insertions(+), 33 deletions(-) diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index c46965ef2..5e49890e0 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -551,6 +551,10 @@ usage! { "--no-acl-check", "Disable ACL check (useful for test environments).", + ARG arg_secretstore_contract: (String) = "none", or |c: &Config| otry!(c.secretstore).service_contract.clone(), + "--secretstore-contract=[SOURCE]", + "Secret Store Service contract source: none, registry (contract address is read from registry) or address.", + ARG arg_secretstore_nodes: (String) = "", or |c: &Config| otry!(c.secretstore).nodes.as_ref().map(|vec| vec.join(",")), "--secretstore-nodes=[NODES]", "Comma-separated list of other secret store cluster nodes in form NODE_PUBLIC_KEY_IN_HEX@NODE_IP_ADDR:NODE_PORT.", @@ -1088,6 +1092,7 @@ struct SecretStore { disable: Option, disable_http: Option, disable_acl_check: Option, + service_contract: Option, self_secret: Option, admin_public: Option, nodes: Option>, @@ -1488,6 +1493,7 @@ mod tests { flag_no_secretstore: false, flag_no_secretstore_http: false, flag_no_secretstore_acl_check: false, + arg_secretstore_contract: "none".into(), arg_secretstore_secret: None, arg_secretstore_admin_public: None, arg_secretstore_nodes: "".into(), @@ -1730,6 +1736,7 @@ mod tests { disable: None, disable_http: None, disable_acl_check: None, + service_contract: None, self_secret: None, admin_public: None, nodes: None, diff --git a/parity/cli/tests/config.full.toml b/parity/cli/tests/config.full.toml index a49717085..9b780c757 100644 --- a/parity/cli/tests/config.full.toml +++ b/parity/cli/tests/config.full.toml @@ -80,6 +80,7 @@ pass = "test_pass" disable = false disable_http = false disable_acl_check = false +service_contract = "none" nodes = [] http_interface = "local" http_port = 8082 diff --git a/parity/configuration.rs b/parity/configuration.rs index 7cb3a84bd..e78cc290f 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -45,7 +45,7 @@ use ethcore_logger::Config as LogConfig; use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path}; use dapps::Configuration as DappsConfiguration; use ipfs::Configuration as IpfsConfiguration; -use secretstore::{Configuration as SecretStoreConfiguration, NodeSecretKey}; +use secretstore::{NodeSecretKey, Configuration as SecretStoreConfiguration, ContractAddress as SecretStoreContractAddress}; use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack}; use run::RunCmd; use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockchain, ExportState, DataFormat}; @@ -606,6 +606,7 @@ impl Configuration { enabled: self.secretstore_enabled(), http_enabled: self.secretstore_http_enabled(), acl_check_enabled: self.secretstore_acl_check_enabled(), + service_contract_address: self.secretstore_service_contract_address()?, self_secret: self.secretstore_self_secret()?, nodes: self.secretstore_nodes()?, interface: self.secretstore_interface(), @@ -1076,6 +1077,14 @@ impl Configuration { !self.args.flag_no_secretstore_acl_check } + fn secretstore_service_contract_address(&self) -> Result, String> { + Ok(match self.args.arg_secretstore_contract.as_ref() { + "none" => None, + "registry" => Some(SecretStoreContractAddress::Registry), + a @ _ => Some(SecretStoreContractAddress::Address(a.parse().map_err(|e| format!("{}", e))?)), + }) + } + fn ui_enabled(&self) -> bool { if self.args.flag_force_ui { return true; diff --git a/parity/secretstore.rs b/parity/secretstore.rs index 7e36ef5e0..06772e74a 100644 --- a/parity/secretstore.rs +++ b/parity/secretstore.rs @@ -24,8 +24,8 @@ use ethsync::SyncProvider; use helpers::replace_home; use util::Address; -#[derive(Debug, PartialEq, Clone)] /// This node secret key. +#[derive(Debug, PartialEq, Clone)] pub enum NodeSecretKey { /// Stored as plain text in configuration file. Plain(Secret), @@ -33,6 +33,15 @@ pub enum NodeSecretKey { KeyStore(Address), } +/// Secret store service contract address. +#[derive(Debug, PartialEq, Clone)] +pub enum ContractAddress { + /// Contract address is read from registry. + Registry, + /// Contract address is specified. + Address(Address), +} + #[derive(Debug, PartialEq, Clone)] /// Secret store configuration pub struct Configuration { @@ -42,6 +51,8 @@ pub struct Configuration { pub http_enabled: bool, /// Is ACL check enabled. pub acl_check_enabled: bool, + /// Service contract address. + pub service_contract_address: Option, /// This node secret. pub self_secret: Option, /// Other nodes IDs + addresses. @@ -93,7 +104,7 @@ mod server { use ethcore_secretstore; use ethkey::KeyPair; use ansi_term::Colour::Red; - use super::{Configuration, Dependencies, NodeSecretKey}; + use super::{Configuration, Dependencies, NodeSecretKey, ContractAddress}; /// Key server pub struct KeyServer { @@ -137,6 +148,10 @@ mod server { address: conf.http_interface.clone(), port: conf.http_port, }) } else { None }, + service_contract_address: conf.service_contract_address.map(|c| match c { + ContractAddress::Registry => ethcore_secretstore::ContractAddress::Registry, + ContractAddress::Address(address) => ethcore_secretstore::ContractAddress::Address(address), + }), data_path: conf.data_path.clone(), acl_check_enabled: conf.acl_check_enabled, cluster_config: ethcore_secretstore::ClusterConfiguration { @@ -175,6 +190,7 @@ impl Default for Configuration { enabled: true, http_enabled: true, acl_check_enabled: true, + service_contract_address: None, self_secret: None, admin_public: None, nodes: BTreeMap::new(), diff --git a/secret_store/src/key_storage.rs b/secret_store/src/key_storage.rs index da698e5e0..020dde700 100644 --- a/secret_store/src/key_storage.rs +++ b/secret_store/src/key_storage.rs @@ -433,6 +433,7 @@ pub mod tests { let tempdir = TempDir::new("").unwrap(); let config = ServiceConfiguration { listener_address: None, + service_contract_address: None, acl_check_enabled: true, data_path: tempdir.path().display().to_string(), cluster_config: ClusterConfiguration { diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs index 3bf6dde06..e996c8295 100644 --- a/secret_store/src/lib.rs +++ b/secret_store/src/lib.rs @@ -66,7 +66,7 @@ use ethcore::client::Client; use ethsync::SyncProvider; pub use types::all::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, - Error, NodeAddress, ServiceConfiguration, ClusterConfiguration}; + Error, NodeAddress, ContractAddress, ServiceConfiguration, ClusterConfiguration}; pub use traits::{NodeKeyPair, KeyServer}; pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair}; @@ -81,20 +81,24 @@ pub fn start(client: Arc, sync: Arc, self_key_pair: Arc Some(listener::http_listener::KeyServerHttpListener::start(listener_address, key_server.clone())?), None => None, }; - let service_contract = Arc::new(listener::service_contract::OnChainServiceContract::new(&client, &sync, self_key_pair.clone())); - let contract_listener = listener::service_contract_listener::ServiceContractListener::new(listener::service_contract_listener::ServiceContractListenerParams { - contract: service_contract, - key_server: key_server.clone(), - self_key_pair: self_key_pair, - key_server_set: key_server_set, - cluster: cluster, - key_storage: key_storage, + let contract_listener = config.service_contract_address.map(|service_contract_address| { + let service_contract = Arc::new(listener::service_contract::OnChainServiceContract::new(&client, &sync, service_contract_address, self_key_pair.clone())); + let contract_listener = listener::service_contract_listener::ServiceContractListener::new(listener::service_contract_listener::ServiceContractListenerParams { + contract: service_contract, + key_server: key_server.clone(), + self_key_pair: self_key_pair, + key_server_set: key_server_set, + cluster: cluster, + key_storage: key_storage, + }); + client.add_notify(contract_listener.clone()); + contract_listener }); - client.add_notify(contract_listener.clone()); - let listener = listener::Listener::new(key_server, http_listener, Some(contract_listener)); - Ok(Box::new(listener)) + Ok(Box::new(listener::Listener::new(key_server, http_listener, contract_listener))) } diff --git a/secret_store/src/listener/service_contract.rs b/secret_store/src/listener/service_contract.rs index cf716846d..28167e487 100644 --- a/secret_store/src/listener/service_contract.rs +++ b/secret_store/src/listener/service_contract.rs @@ -26,7 +26,7 @@ use hash::keccak; use bigint::hash::H256; use bigint::prelude::U256; use listener::service_contract_listener::ServiceTask; -use {ServerKeyId, NodeKeyPair}; +use {ServerKeyId, NodeKeyPair, ContractAddress}; /// Name of the SecretStore contract in the registry. const SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service"; @@ -60,6 +60,8 @@ pub struct OnChainServiceContract { sync: Weak, /// This node key pair. self_key_pair: Arc, + /// Contract addresss. + address: ContractAddress, /// Contract. contract: RwLock>, } @@ -80,19 +82,27 @@ struct PendingRequestsIterator { impl OnChainServiceContract { /// Create new on-chain service contract. - pub fn new(client: &Arc, sync: &Arc, self_key_pair: Arc) -> Self { - let contract_addr = client.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned()) - .map(|address| { + pub fn new(client: &Arc, sync: &Arc, address: ContractAddress, self_key_pair: Arc) -> Self { + let contract_addr = match &address { + &ContractAddress::Registry => client.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned()) + .map(|address| { + trace!(target: "secretstore", "{}: installing service contract from address {}", + self_key_pair.public(), address); + address + }) + .unwrap_or_default(), + &ContractAddress::Address(ref address) => { trace!(target: "secretstore", "{}: installing service contract from address {}", self_key_pair.public(), address); - address - }) - .unwrap_or_default(); + address.clone() + }, + }; OnChainServiceContract { client: Arc::downgrade(client), sync: Arc::downgrade(sync), self_key_pair: self_key_pair, + address: address, contract: RwLock::new(Arc::new(SecretStoreService::new(contract_addr))), } } @@ -100,18 +110,20 @@ impl OnChainServiceContract { impl ServiceContract for OnChainServiceContract { fn update(&self) { - if let (Some(client), Some(sync)) = (self.client.upgrade(), self.sync.upgrade()) { - // do nothing until synced - if sync.status().is_syncing(client.queue_info()) { - return; - } + if let &ContractAddress::Registry = &self.address { + if let (Some(client), Some(sync)) = (self.client.upgrade(), self.sync.upgrade()) { + // do nothing until synced + if sync.status().is_syncing(client.queue_info()) { + return; + } - // update contract address from registry - let service_contract_addr = client.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned()).unwrap_or_default(); - if self.contract.read().address != service_contract_addr { - trace!(target: "secretstore", "{}: installing service contract from address {}", - self.self_key_pair.public(), service_contract_addr); - *self.contract.write() = Arc::new(SecretStoreService::new(service_contract_addr)); + // update contract address from registry + let service_contract_addr = client.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned()).unwrap_or_default(); + if self.contract.read().address != service_contract_addr { + trace!(target: "secretstore", "{}: installing service contract from address {}", + self.self_key_pair.public(), service_contract_addr); + *self.contract.write() = Arc::new(SecretStoreService::new(service_contract_addr)); + } } } } diff --git a/secret_store/src/types/all.rs b/secret_store/src/types/all.rs index 7c746f2a0..8738ba032 100644 --- a/secret_store/src/types/all.rs +++ b/secret_store/src/types/all.rs @@ -61,11 +61,22 @@ pub struct NodeAddress { pub port: u16, } +/// Contract address. +#[derive(Debug, Clone)] +pub enum ContractAddress { + /// Address is read from registry. + Registry, + /// Address is specified. + Address(ethkey::Address), +} + /// Secret store configuration #[derive(Debug)] pub struct ServiceConfiguration { /// HTTP listener address. If None, HTTP API is disabled. pub listener_address: Option, + /// Service contract address. If None, service contract API is disabled. + pub service_contract_address: Option, /// Is ACL check enabled. If false, everyone has access to all keys. Useful for tests only. pub acl_check_enabled: bool, /// Data directory path for secret store