SecretStore: cli option to configure service contract

This commit is contained in:
Svyatoslav Nikolsky 2017-11-24 12:33:33 +03:00
parent 30816d8155
commit 14686f2652
8 changed files with 94 additions and 33 deletions

View File

@ -551,6 +551,10 @@ usage! {
"--no-acl-check", "--no-acl-check",
"Disable ACL check (useful for test environments).", "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(",")), ARG arg_secretstore_nodes: (String) = "", or |c: &Config| otry!(c.secretstore).nodes.as_ref().map(|vec| vec.join(",")),
"--secretstore-nodes=[NODES]", "--secretstore-nodes=[NODES]",
"Comma-separated list of other secret store cluster nodes in form NODE_PUBLIC_KEY_IN_HEX@NODE_IP_ADDR:NODE_PORT.", "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<bool>, disable: Option<bool>,
disable_http: Option<bool>, disable_http: Option<bool>,
disable_acl_check: Option<bool>, disable_acl_check: Option<bool>,
service_contract: Option<String>,
self_secret: Option<String>, self_secret: Option<String>,
admin_public: Option<String>, admin_public: Option<String>,
nodes: Option<Vec<String>>, nodes: Option<Vec<String>>,
@ -1488,6 +1493,7 @@ mod tests {
flag_no_secretstore: false, flag_no_secretstore: false,
flag_no_secretstore_http: false, flag_no_secretstore_http: false,
flag_no_secretstore_acl_check: false, flag_no_secretstore_acl_check: false,
arg_secretstore_contract: "none".into(),
arg_secretstore_secret: None, arg_secretstore_secret: None,
arg_secretstore_admin_public: None, arg_secretstore_admin_public: None,
arg_secretstore_nodes: "".into(), arg_secretstore_nodes: "".into(),
@ -1730,6 +1736,7 @@ mod tests {
disable: None, disable: None,
disable_http: None, disable_http: None,
disable_acl_check: None, disable_acl_check: None,
service_contract: None,
self_secret: None, self_secret: None,
admin_public: None, admin_public: None,
nodes: None, nodes: None,

View File

@ -80,6 +80,7 @@ pass = "test_pass"
disable = false disable = false
disable_http = false disable_http = false
disable_acl_check = false disable_acl_check = false
service_contract = "none"
nodes = [] nodes = []
http_interface = "local" http_interface = "local"
http_port = 8082 http_port = 8082

View File

@ -45,7 +45,7 @@ use ethcore_logger::Config as LogConfig;
use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path}; use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path};
use dapps::Configuration as DappsConfiguration; use dapps::Configuration as DappsConfiguration;
use ipfs::Configuration as IpfsConfiguration; 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 updater::{UpdatePolicy, UpdateFilter, ReleaseTrack};
use run::RunCmd; use run::RunCmd;
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockchain, ExportState, DataFormat}; use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, KillBlockchain, ExportState, DataFormat};
@ -606,6 +606,7 @@ impl Configuration {
enabled: self.secretstore_enabled(), enabled: self.secretstore_enabled(),
http_enabled: self.secretstore_http_enabled(), http_enabled: self.secretstore_http_enabled(),
acl_check_enabled: self.secretstore_acl_check_enabled(), acl_check_enabled: self.secretstore_acl_check_enabled(),
service_contract_address: self.secretstore_service_contract_address()?,
self_secret: self.secretstore_self_secret()?, self_secret: self.secretstore_self_secret()?,
nodes: self.secretstore_nodes()?, nodes: self.secretstore_nodes()?,
interface: self.secretstore_interface(), interface: self.secretstore_interface(),
@ -1076,6 +1077,14 @@ impl Configuration {
!self.args.flag_no_secretstore_acl_check !self.args.flag_no_secretstore_acl_check
} }
fn secretstore_service_contract_address(&self) -> Result<Option<SecretStoreContractAddress>, 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 { fn ui_enabled(&self) -> bool {
if self.args.flag_force_ui { if self.args.flag_force_ui {
return true; return true;

View File

@ -24,8 +24,8 @@ use ethsync::SyncProvider;
use helpers::replace_home; use helpers::replace_home;
use util::Address; use util::Address;
#[derive(Debug, PartialEq, Clone)]
/// This node secret key. /// This node secret key.
#[derive(Debug, PartialEq, Clone)]
pub enum NodeSecretKey { pub enum NodeSecretKey {
/// Stored as plain text in configuration file. /// Stored as plain text in configuration file.
Plain(Secret), Plain(Secret),
@ -33,6 +33,15 @@ pub enum NodeSecretKey {
KeyStore(Address), 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)] #[derive(Debug, PartialEq, Clone)]
/// Secret store configuration /// Secret store configuration
pub struct Configuration { pub struct Configuration {
@ -42,6 +51,8 @@ pub struct Configuration {
pub http_enabled: bool, pub http_enabled: bool,
/// Is ACL check enabled. /// Is ACL check enabled.
pub acl_check_enabled: bool, pub acl_check_enabled: bool,
/// Service contract address.
pub service_contract_address: Option<ContractAddress>,
/// This node secret. /// This node secret.
pub self_secret: Option<NodeSecretKey>, pub self_secret: Option<NodeSecretKey>,
/// Other nodes IDs + addresses. /// Other nodes IDs + addresses.
@ -93,7 +104,7 @@ mod server {
use ethcore_secretstore; use ethcore_secretstore;
use ethkey::KeyPair; use ethkey::KeyPair;
use ansi_term::Colour::Red; use ansi_term::Colour::Red;
use super::{Configuration, Dependencies, NodeSecretKey}; use super::{Configuration, Dependencies, NodeSecretKey, ContractAddress};
/// Key server /// Key server
pub struct KeyServer { pub struct KeyServer {
@ -137,6 +148,10 @@ mod server {
address: conf.http_interface.clone(), address: conf.http_interface.clone(),
port: conf.http_port, port: conf.http_port,
}) } else { None }, }) } 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(), data_path: conf.data_path.clone(),
acl_check_enabled: conf.acl_check_enabled, acl_check_enabled: conf.acl_check_enabled,
cluster_config: ethcore_secretstore::ClusterConfiguration { cluster_config: ethcore_secretstore::ClusterConfiguration {
@ -175,6 +190,7 @@ impl Default for Configuration {
enabled: true, enabled: true,
http_enabled: true, http_enabled: true,
acl_check_enabled: true, acl_check_enabled: true,
service_contract_address: None,
self_secret: None, self_secret: None,
admin_public: None, admin_public: None,
nodes: BTreeMap::new(), nodes: BTreeMap::new(),

View File

@ -433,6 +433,7 @@ pub mod tests {
let tempdir = TempDir::new("").unwrap(); let tempdir = TempDir::new("").unwrap();
let config = ServiceConfiguration { let config = ServiceConfiguration {
listener_address: None, listener_address: None,
service_contract_address: None,
acl_check_enabled: true, acl_check_enabled: true,
data_path: tempdir.path().display().to_string(), data_path: tempdir.path().display().to_string(),
cluster_config: ClusterConfiguration { cluster_config: ClusterConfiguration {

View File

@ -66,7 +66,7 @@ use ethcore::client::Client;
use ethsync::SyncProvider; use ethsync::SyncProvider;
pub use types::all::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public, pub use types::all::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public,
Error, NodeAddress, ServiceConfiguration, ClusterConfiguration}; Error, NodeAddress, ContractAddress, ServiceConfiguration, ClusterConfiguration};
pub use traits::{NodeKeyPair, KeyServer}; pub use traits::{NodeKeyPair, KeyServer};
pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair}; pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair};
@ -81,20 +81,24 @@ pub fn start(client: Arc<Client>, sync: Arc<SyncProvider>, self_key_pair: Arc<No
let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(&config)?); let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(&config)?);
let key_server = Arc::new(key_server::KeyServerImpl::new(&config.cluster_config, key_server_set.clone(), self_key_pair.clone(), acl_storage, key_storage.clone())?); let key_server = Arc::new(key_server::KeyServerImpl::new(&config.cluster_config, key_server_set.clone(), self_key_pair.clone(), acl_storage, key_storage.clone())?);
let cluster = key_server.cluster(); let cluster = key_server.cluster();
// prepare listeners
let http_listener = match config.listener_address { let http_listener = match config.listener_address {
Some(listener_address) => Some(listener::http_listener::KeyServerHttpListener::start(listener_address, key_server.clone())?), Some(listener_address) => Some(listener::http_listener::KeyServerHttpListener::start(listener_address, key_server.clone())?),
None => None, None => None,
}; };
let service_contract = Arc::new(listener::service_contract::OnChainServiceContract::new(&client, &sync, self_key_pair.clone())); let contract_listener = config.service_contract_address.map(|service_contract_address| {
let contract_listener = listener::service_contract_listener::ServiceContractListener::new(listener::service_contract_listener::ServiceContractListenerParams { let service_contract = Arc::new(listener::service_contract::OnChainServiceContract::new(&client, &sync, service_contract_address, self_key_pair.clone()));
contract: service_contract, let contract_listener = listener::service_contract_listener::ServiceContractListener::new(listener::service_contract_listener::ServiceContractListenerParams {
key_server: key_server.clone(), contract: service_contract,
self_key_pair: self_key_pair, key_server: key_server.clone(),
key_server_set: key_server_set, self_key_pair: self_key_pair,
cluster: cluster, key_server_set: key_server_set,
key_storage: key_storage, cluster: cluster,
key_storage: key_storage,
});
client.add_notify(contract_listener.clone());
contract_listener
}); });
client.add_notify(contract_listener.clone()); Ok(Box::new(listener::Listener::new(key_server, http_listener, contract_listener)))
let listener = listener::Listener::new(key_server, http_listener, Some(contract_listener));
Ok(Box::new(listener))
} }

View File

@ -26,7 +26,7 @@ use hash::keccak;
use bigint::hash::H256; use bigint::hash::H256;
use bigint::prelude::U256; use bigint::prelude::U256;
use listener::service_contract_listener::ServiceTask; use listener::service_contract_listener::ServiceTask;
use {ServerKeyId, NodeKeyPair}; use {ServerKeyId, NodeKeyPair, ContractAddress};
/// Name of the SecretStore contract in the registry. /// Name of the SecretStore contract in the registry.
const SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service"; const SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service";
@ -60,6 +60,8 @@ pub struct OnChainServiceContract {
sync: Weak<SyncProvider>, sync: Weak<SyncProvider>,
/// This node key pair. /// This node key pair.
self_key_pair: Arc<NodeKeyPair>, self_key_pair: Arc<NodeKeyPair>,
/// Contract addresss.
address: ContractAddress,
/// Contract. /// Contract.
contract: RwLock<Arc<SecretStoreService>>, contract: RwLock<Arc<SecretStoreService>>,
} }
@ -80,19 +82,27 @@ struct PendingRequestsIterator {
impl OnChainServiceContract { impl OnChainServiceContract {
/// Create new on-chain service contract. /// Create new on-chain service contract.
pub fn new(client: &Arc<Client>, sync: &Arc<SyncProvider>, self_key_pair: Arc<NodeKeyPair>) -> Self { pub fn new(client: &Arc<Client>, sync: &Arc<SyncProvider>, address: ContractAddress, self_key_pair: Arc<NodeKeyPair>) -> Self {
let contract_addr = client.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned()) let contract_addr = match &address {
.map(|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 {}", trace!(target: "secretstore", "{}: installing service contract from address {}",
self_key_pair.public(), address); self_key_pair.public(), address);
address address.clone()
}) },
.unwrap_or_default(); };
OnChainServiceContract { OnChainServiceContract {
client: Arc::downgrade(client), client: Arc::downgrade(client),
sync: Arc::downgrade(sync), sync: Arc::downgrade(sync),
self_key_pair: self_key_pair, self_key_pair: self_key_pair,
address: address,
contract: RwLock::new(Arc::new(SecretStoreService::new(contract_addr))), contract: RwLock::new(Arc::new(SecretStoreService::new(contract_addr))),
} }
} }
@ -100,18 +110,20 @@ impl OnChainServiceContract {
impl ServiceContract for OnChainServiceContract { impl ServiceContract for OnChainServiceContract {
fn update(&self) { fn update(&self) {
if let (Some(client), Some(sync)) = (self.client.upgrade(), self.sync.upgrade()) { if let &ContractAddress::Registry = &self.address {
// do nothing until synced if let (Some(client), Some(sync)) = (self.client.upgrade(), self.sync.upgrade()) {
if sync.status().is_syncing(client.queue_info()) { // do nothing until synced
return; if sync.status().is_syncing(client.queue_info()) {
} return;
}
// update contract address from registry // update contract address from registry
let service_contract_addr = client.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned()).unwrap_or_default(); let service_contract_addr = client.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned()).unwrap_or_default();
if self.contract.read().address != service_contract_addr { if self.contract.read().address != service_contract_addr {
trace!(target: "secretstore", "{}: installing service contract from address {}", trace!(target: "secretstore", "{}: installing service contract from address {}",
self.self_key_pair.public(), service_contract_addr); self.self_key_pair.public(), service_contract_addr);
*self.contract.write() = Arc::new(SecretStoreService::new(service_contract_addr)); *self.contract.write() = Arc::new(SecretStoreService::new(service_contract_addr));
}
} }
} }
} }

View File

@ -61,11 +61,22 @@ pub struct NodeAddress {
pub port: u16, 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 /// Secret store configuration
#[derive(Debug)] #[derive(Debug)]
pub struct ServiceConfiguration { pub struct ServiceConfiguration {
/// HTTP listener address. If None, HTTP API is disabled. /// HTTP listener address. If None, HTTP API is disabled.
pub listener_address: Option<NodeAddress>, pub listener_address: Option<NodeAddress>,
/// Service contract address. If None, service contract API is disabled.
pub service_contract_address: Option<ContractAddress>,
/// Is ACL check enabled. If false, everyone has access to all keys. Useful for tests only. /// Is ACL check enabled. If false, everyone has access to all keys. Useful for tests only.
pub acl_check_enabled: bool, pub acl_check_enabled: bool,
/// Data directory path for secret store /// Data directory path for secret store