SecretStore: TrustedClient
This commit is contained in:
parent
794de9f743
commit
d7650e2b9c
@ -14,17 +14,17 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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<Client>,
|
||||
/// Sync provider.
|
||||
sync: Weak<SyncProvider>,
|
||||
client: TrustedClient,
|
||||
/// Contract address.
|
||||
contract_addr: Option<Address>,
|
||||
/// Contract at given address.
|
||||
@ -60,12 +58,15 @@ pub struct DummyAclStorage {
|
||||
}
|
||||
|
||||
impl OnChainAclStorage {
|
||||
pub fn new(client: &Arc<Client>, sync: &Arc<SyncProvider>) -> Arc<Self> {
|
||||
pub fn new(trusted_client: TrustedClient) -> Result<Arc<Self>, 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<Client>, sync: &Arc<SyncProvider>) -> 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<bool, Error> {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -14,20 +14,20 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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<Client>,
|
||||
/// Sync provider.
|
||||
sync: Weak<SyncProvider>,
|
||||
client: TrustedClient,
|
||||
/// Contract address.
|
||||
contract_addr: Option<Address>,
|
||||
/// Active set of key servers.
|
||||
@ -66,19 +64,14 @@ struct CachedContract {
|
||||
}
|
||||
|
||||
impl OnChainKeyServerSet {
|
||||
pub fn new(client: &Arc<Client>, sync: &Arc<SyncProvider>, key_servers: BTreeMap<Public, NodeAddress>) -> Result<Arc<Self>, 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<Public, NodeAddress>) -> Result<Arc<Self>, 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<Client>, sync: &Arc<SyncProvider>, key_servers: BTreeMap<Public, NodeAddress>) -> Result<Self, Error> {
|
||||
Ok(CachedContract {
|
||||
client: Arc::downgrade(client),
|
||||
sync: Arc::downgrade(sync),
|
||||
pub fn new(client: TrustedClient, key_servers: BTreeMap<Public, NodeAddress>) -> Result<Self, Error> {
|
||||
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::<Result<BTreeMap<_, _>, 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<H256>, retracted: Vec<H256>) {
|
||||
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
|
||||
|
@ -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<Client>, sync: Arc<SyncProvider>, self_key_pair: Arc<NodeKeyPair>, config: ServiceConfiguration) -> Result<Box<KeyServer>, Error> {
|
||||
let trusted_client = trusted_client::TrustedClient::new(client.clone(), sync);
|
||||
let acl_storage: Arc<acl_storage::AclStorage> = 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<Client>, sync: Arc<SyncProvider>, self_key_pair: Arc<No
|
||||
None => 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(),
|
||||
|
@ -14,18 +14,18 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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<Client>,
|
||||
/// Sync provider.
|
||||
sync: Weak<SyncProvider>,
|
||||
client: TrustedClient,
|
||||
/// This node key pair.
|
||||
self_key_pair: Arc<NodeKeyPair>,
|
||||
/// Contract addresss.
|
||||
@ -82,14 +80,14 @@ struct PendingRequestsIterator {
|
||||
|
||||
impl OnChainServiceContract {
|
||||
/// Create new on-chain service contract.
|
||||
pub fn new(client: &Arc<Client>, sync: &Arc<SyncProvider>, address: ContractAddress, self_key_pair: Arc<NodeKeyPair>) -> Self {
|
||||
pub fn new(client: TrustedClient, address: ContractAddress, self_key_pair: Arc<NodeKeyPair>) -> 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<Iterator<Item=Vec<H256>>> {
|
||||
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<Iterator<Item=(bool, ServiceTask)>> {
|
||||
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
|
||||
|
57
secret_store/src/trusted_client.rs
Normal file
57
secret_store/src/trusted_client.rs
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
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<Client>,
|
||||
/// Sync provider.
|
||||
sync: Weak<SyncProvider>,
|
||||
}
|
||||
|
||||
impl TrustedClient {
|
||||
/// Create new trusted client.
|
||||
pub fn new(client: Arc<Client>, sync: Arc<SyncProvider>) -> 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<Arc<Client>> {
|
||||
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<Arc<Client>> {
|
||||
self.client.upgrade()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user