diff --git a/secret_store/src/acl_storage.rs b/secret_store/src/acl_storage.rs
index 8d629f022..e5637f81c 100644
--- a/secret_store/src/acl_storage.rs
+++ b/secret_store/src/acl_storage.rs
@@ -14,17 +14,17 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use std::sync::{Arc, Weak};
+use std::sync::Arc;
use std::collections::{HashMap, HashSet};
use futures::{future, Future};
use parking_lot::{Mutex, RwLock};
use ethkey::public_to_address;
-use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify};
-use ethsync::SyncProvider;
+use ethcore::client::{BlockChainClient, BlockId, ChainNotify};
use native_contracts::SecretStoreAclStorage;
use bigint::hash::H256;
use util::Address;
use bytes::Bytes;
+use trusted_client::TrustedClient;
use types::all::{Error, ServerKeyId, Public};
const ACL_CHECKER_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_acl_checker";
@@ -44,9 +44,7 @@ pub struct OnChainAclStorage {
/// Cached on-chain ACL storage contract.
struct CachedContract {
/// Blockchain client.
- client: Weak,
- /// Sync provider.
- sync: Weak,
+ client: TrustedClient,
/// Contract address.
contract_addr: Option,
/// Contract at given address.
@@ -60,12 +58,15 @@ pub struct DummyAclStorage {
}
impl OnChainAclStorage {
- pub fn new(client: &Arc, sync: &Arc) -> Arc {
+ pub fn new(trusted_client: TrustedClient) -> Result, Error> {
+ let client = trusted_client.get_untrusted();
let acl_storage = Arc::new(OnChainAclStorage {
- contract: Mutex::new(CachedContract::new(client, sync)),
+ contract: Mutex::new(CachedContract::new(trusted_client)),
});
- client.add_notify(acl_storage.clone());
- acl_storage
+ client
+ .ok_or(Error::Internal("Constructing OnChainAclStorage without active Client".into()))?
+ .add_notify(acl_storage.clone());
+ Ok(acl_storage)
}
}
@@ -84,17 +85,16 @@ impl ChainNotify for OnChainAclStorage {
}
impl CachedContract {
- pub fn new(client: &Arc, sync: &Arc) -> Self {
+ pub fn new(client: TrustedClient) -> Self {
CachedContract {
- client: Arc::downgrade(client),
- sync: Arc::downgrade(sync),
+ client: client,
contract_addr: None,
contract: None,
}
}
pub fn update(&mut self) {
- if let Some(client) = self.client.upgrade() {
+ if let Some(client) = self.client.get() {
let new_contract_addr = client.registry_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.to_owned());
if self.contract_addr.as_ref() != new_contract_addr.as_ref() {
self.contract = new_contract_addr.map(|contract_addr| {
@@ -109,26 +109,20 @@ impl CachedContract {
}
pub fn check(&mut self, public: &Public, document: &ServerKeyId) -> Result {
- match (self.client.upgrade(), self.sync.upgrade()) {
- (Some(client), Some(sync)) => {
- // we can not tell if access to document is allowed until fully synchronized
- if sync.status().is_syncing(client.queue_info()) {
- return Err(Error::Internal("Trying to check access by non-synchronized client".to_owned()));
- }
-
- // call contract to check accesss
- match self.contract.as_ref() {
- Some(contract) => {
- let address = public_to_address(&public);
- let do_call = |a, d| future::done(client.call_contract(BlockId::Latest, a, d));
- contract.check_permissions(do_call, address, document.clone())
- .map_err(|err| Error::Internal(err))
- .wait()
- },
- None => Err(Error::Internal("ACL checker contract is not configured".to_owned())),
- }
- },
- _ => Err(Error::Internal("Calling ACL contract without client".into())),
+ if let Some(client) = self.client.get() {
+ // call contract to check accesss
+ match self.contract.as_ref() {
+ Some(contract) => {
+ let address = public_to_address(&public);
+ let do_call = |a, d| future::done(client.call_contract(BlockId::Latest, a, d));
+ contract.check_permissions(do_call, address, document.clone())
+ .map_err(|err| Error::Internal(err))
+ .wait()
+ },
+ None => Err(Error::Internal("ACL checker contract is not configured".to_owned())),
+ }
+ } else {
+ Err(Error::Internal("Calling ACL contract without trusted blockchain client".into()))
}
}
}
diff --git a/secret_store/src/key_server_set.rs b/secret_store/src/key_server_set.rs
index 04647db41..e64123a7f 100644
--- a/secret_store/src/key_server_set.rs
+++ b/secret_store/src/key_server_set.rs
@@ -14,20 +14,20 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use std::sync::{Arc, Weak};
+use std::sync::Arc;
use std::net::SocketAddr;
use std::collections::BTreeMap;
use futures::{future, Future};
use parking_lot::Mutex;
use ethcore::filter::Filter;
use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify};
-use ethsync::SyncProvider;
use native_contracts::KeyServerSet as KeyServerSetContract;
use hash::keccak;
use bigint::hash::H256;
use util::Address;
use bytes::Bytes;
use types::all::{Error, Public, NodeAddress};
+use trusted_client::TrustedClient;
const KEY_SERVER_SET_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_server_set";
@@ -56,9 +56,7 @@ pub struct OnChainKeyServerSet {
/// Cached on-chain Key Server set contract.
struct CachedContract {
/// Blockchain client.
- client: Weak,
- /// Sync provider.
- sync: Weak,
+ client: TrustedClient,
/// Contract address.
contract_addr: Option,
/// Active set of key servers.
@@ -66,19 +64,14 @@ struct CachedContract {
}
impl OnChainKeyServerSet {
- pub fn new(client: &Arc, sync: &Arc, key_servers: BTreeMap) -> Result, Error> {
- let mut cached_contract = CachedContract::new(client, sync, key_servers)?;
- let key_server_contract_address = client.registry_address(KEY_SERVER_SET_CONTRACT_REGISTRY_NAME.to_owned());
- // only initialize from contract if it is installed. otherwise - use default nodes
- // once the contract is installed, all default nodes are lost (if not in the contract' set)
- if key_server_contract_address.is_some() {
- cached_contract.read_from_registry(&*client, key_server_contract_address);
- }
-
+ pub fn new(trusted_client: TrustedClient, key_servers: BTreeMap) -> Result, Error> {
+ let client = trusted_client.get_untrusted();
let key_server_set = Arc::new(OnChainKeyServerSet {
- contract: Mutex::new(cached_contract),
+ contract: Mutex::new(CachedContract::new(trusted_client, key_servers)?),
});
- client.add_notify(key_server_set.clone());
+ client
+ .ok_or(Error::Internal("Constructing OnChainKeyServerSet without active Client".into()))?
+ .add_notify(key_server_set.clone());
Ok(key_server_set)
}
}
@@ -98,10 +91,9 @@ impl ChainNotify for OnChainKeyServerSet {
}
impl CachedContract {
- pub fn new(client: &Arc, sync: &Arc, key_servers: BTreeMap) -> Result {
- Ok(CachedContract {
- client: Arc::downgrade(client),
- sync: Arc::downgrade(sync),
+ pub fn new(client: TrustedClient, key_servers: BTreeMap) -> Result {
+ let mut cached_contract = CachedContract {
+ client: client,
contract_addr: None,
key_servers: key_servers.into_iter()
.map(|(p, addr)| {
@@ -110,16 +102,22 @@ impl CachedContract {
Ok((p, addr))
})
.collect::, Error>>()?,
- })
+ };
+
+ if let Some(client) = cached_contract.client.get() {
+ let key_server_contract_address = client.registry_address(KEY_SERVER_SET_CONTRACT_REGISTRY_NAME.to_owned());
+ // only initialize from contract if it is installed. otherwise - use default nodes
+ // once the contract is installed, all default nodes are lost (if not in the contract' set)
+ if key_server_contract_address.is_some() {
+ cached_contract.read_from_registry(&*client, key_server_contract_address);
+ }
+ }
+
+ Ok(cached_contract)
}
pub fn update(&mut self, enacted: Vec, retracted: Vec) {
- if let (Some(client), Some(sync)) = (self.client.upgrade(), self.sync.upgrade()) {
- // do not update initial server set until fully synchronized
- if sync.status().is_syncing(client.queue_info()) {
- return;
- }
-
+ if let Some(client) = self.client.get() {
let new_contract_addr = client.registry_address(KEY_SERVER_SET_CONTRACT_REGISTRY_NAME.to_owned());
// new contract installed => read nodes set from the contract
diff --git a/secret_store/src/lib.rs b/secret_store/src/lib.rs
index b2139c000..d2eb7b125 100644
--- a/secret_store/src/lib.rs
+++ b/secret_store/src/lib.rs
@@ -60,6 +60,7 @@ mod serialization;
mod key_server_set;
mod node_key_pair;
mod listener;
+mod trusted_client;
use std::sync::Arc;
use ethcore::client::Client;
@@ -72,12 +73,13 @@ pub use self::node_key_pair::{PlainNodeKeyPair, KeyStoreNodeKeyPair};
/// Start new key server instance
pub fn start(client: Arc, sync: Arc, self_key_pair: Arc, config: ServiceConfiguration) -> Result, Error> {
+ let trusted_client = trusted_client::TrustedClient::new(client.clone(), sync);
let acl_storage: Arc = if config.acl_check_enabled {
- acl_storage::OnChainAclStorage::new(&client, &sync)
+ acl_storage::OnChainAclStorage::new(trusted_client.clone())?
} else {
Arc::new(acl_storage::DummyAclStorage::default())
};
- let key_server_set = key_server_set::OnChainKeyServerSet::new(&client, &sync, config.cluster_config.nodes.clone())?;
+ let key_server_set = key_server_set::OnChainKeyServerSet::new(trusted_client.clone(), config.cluster_config.nodes.clone())?;
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 cluster = key_server.cluster();
@@ -88,7 +90,7 @@ pub fn start(client: Arc, sync: Arc, self_key_pair: Arc None,
};
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 service_contract = Arc::new(listener::service_contract::OnChainServiceContract::new(trusted_client, 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(),
diff --git a/secret_store/src/listener/service_contract.rs b/secret_store/src/listener/service_contract.rs
index 7330571f6..0104836ac 100644
--- a/secret_store/src/listener/service_contract.rs
+++ b/secret_store/src/listener/service_contract.rs
@@ -14,18 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
-use std::sync::{Arc, Weak};
+use std::sync::Arc;
use futures::{future, Future};
use parking_lot::RwLock;
use ethcore::filter::Filter;
use ethcore::client::{Client, BlockChainClient, BlockId};
use ethkey::{Public, Signature, public_to_address};
-use ethsync::SyncProvider;
use native_contracts::SecretStoreService;
use hash::keccak;
use bigint::hash::H256;
use bigint::prelude::U256;
use listener::service_contract_listener::ServiceTask;
+use trusted_client::TrustedClient;
use {ServerKeyId, NodeKeyPair, ContractAddress};
/// Name of the SecretStore contract in the registry.
@@ -55,9 +55,7 @@ pub trait ServiceContract: Send + Sync {
/// On-chain service contract.
pub struct OnChainServiceContract {
/// Blockchain client.
- client: Weak,
- /// Sync provider.
- sync: Weak,
+ client: TrustedClient,
/// This node key pair.
self_key_pair: Arc,
/// Contract addresss.
@@ -82,14 +80,14 @@ struct PendingRequestsIterator {
impl OnChainServiceContract {
/// Create new on-chain service contract.
- pub fn new(client: &Arc, sync: &Arc, address: ContractAddress, self_key_pair: Arc) -> Self {
+ pub fn new(client: TrustedClient, address: ContractAddress, self_key_pair: Arc) -> Self {
let contract_addr = match address {
- ContractAddress::Registry => client.registry_address(SERVICE_CONTRACT_REGISTRY_NAME.to_owned())
+ ContractAddress::Registry => client.get().and_then(|c| c.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 {}",
@@ -99,8 +97,7 @@ impl OnChainServiceContract {
};
OnChainServiceContract {
- client: Arc::downgrade(client),
- sync: Arc::downgrade(sync),
+ client: client,
self_key_pair: self_key_pair,
address: address,
contract: RwLock::new(Arc::new(SecretStoreService::new(contract_addr))),
@@ -111,12 +108,7 @@ impl OnChainServiceContract {
impl ServiceContract for OnChainServiceContract {
fn update(&self) {
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;
- }
-
+ if let Some(client) = self.client.get() {
// 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 {
@@ -130,14 +122,12 @@ impl ServiceContract for OnChainServiceContract {
fn is_actual(&self) -> bool {
self.contract.read().address != Default::default()
- && match (self.client.upgrade(), self.sync.upgrade()) {
- (Some(client), Some(sync)) => !sync.status().is_syncing(client.queue_info()),
- _ => false,
- }
+ && self.client.get().is_some()
}
fn read_logs(&self, first_block: H256, last_block: H256) -> Box>> {
- let client = match self.client.upgrade() {
+ // already bound to specific blocks => do not care about trust here
+ let client = match self.client.get_untrusted() {
Some(client) => client,
None => {
warn!(target: "secretstore", "{}: client is offline during read_pending_requests call",
@@ -165,10 +155,10 @@ impl ServiceContract for OnChainServiceContract {
}
fn read_pending_requests(&self) -> Box> {
- let client = match self.client.upgrade() {
+ let client = match self.client.get() {
Some(client) => client,
None => {
- warn!(target: "secretstore", "{}: client is offline during read_pending_requests call",
+ warn!(target: "secretstore", "{}: client is untrusted during read_pending_requests call",
self.self_key_pair.public());
return Box::new(::std::iter::empty());
},
@@ -205,9 +195,10 @@ impl ServiceContract for OnChainServiceContract {
// it is not an error, because key could be generated even without contract
return Ok(());
}
- let client = match self.client.upgrade() {
+
+ let client = match self.client.get() {
Some(client) => client,
- None => return Err("client is required to publish key".into()),
+ None => return Err("trusted client is required to publish key".into()),
};
// only publish key if contract waits for publication
diff --git a/secret_store/src/trusted_client.rs b/secret_store/src/trusted_client.rs
new file mode 100644
index 000000000..688e4099d
--- /dev/null
+++ b/secret_store/src/trusted_client.rs
@@ -0,0 +1,57 @@
+// Copyright 2015-2017 Parity Technologies (UK) Ltd.
+// This file is part of Parity.
+
+// Parity is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity. If not, see .
+
+use std::sync::{Arc, Weak};
+use ethcore::client::{Client, BlockChainClient};
+use ethsync::SyncProvider;
+
+#[derive(Clone)]
+/// 'Trusted' client weak reference.
+pub struct TrustedClient {
+ /// Blockchain client.
+ client: Weak,
+ /// Sync provider.
+ sync: Weak,
+}
+
+impl TrustedClient {
+ /// Create new trusted client.
+ pub fn new(client: Arc, sync: Arc) -> Self {
+ TrustedClient {
+ client: Arc::downgrade(&client),
+ sync: Arc::downgrade(&sync),
+ }
+ }
+
+ /// Get 'trusted' `Client` reference only if it is synchronized && trusted.
+ pub fn get(&self) -> Option> {
+ self.client.upgrade()
+ .and_then(|client| self.sync.upgrade().map(|sync| (client, sync)))
+ .and_then(|(client, sync)| {
+ let is_synced = !sync.status().is_syncing(client.queue_info());
+ let is_trusted = client.chain_info().security_level().is_full();
+ match is_synced && is_trusted {
+ true => Some(client),
+ false => None,
+ }
+ })
+ }
+
+ /// Get untrusted `Client` reference.
+ pub fn get_untrusted(&self) -> Option> {
+ self.client.upgrade()
+ }
+}