Encapsulate access to the client for secret store (#11232)
* Move all client usages into trusted_client * Move confirmed hash method to trusted client * Tree route and logs encapsuluted * Remove not used method for keys sharing * NodeKeyPair renamed and moved to trusted client * Use public key error in trusted client * Move contract address definition into trusted client * Block id and number types from ethcore wrapped * Trusted client renamed to more general Blockchain * Trusted client implementation moved to parity code * Move node key pair under secret store feature as well * Registar crate removed from deps * Accounts feature removed from secret store * Fix after merge * Blockchain renamed to SecretStoreChain * Module documentations added
This commit is contained in:
parent
5bd6b208af
commit
424b38a8d7
9
Cargo.lock
generated
9
Cargo.lock
generated
@ -1477,16 +1477,10 @@ name = "ethcore-secretstore"
|
|||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"client-traits 0.1.0",
|
|
||||||
"common-types 0.1.0",
|
|
||||||
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethabi 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethabi 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethabi-contract 9.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethabi-contract 9.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethabi-derive 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethabi-derive 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethcore 1.12.0",
|
|
||||||
"ethcore-accounts 0.1.0",
|
|
||||||
"ethcore-call-contract 0.1.0",
|
|
||||||
"ethcore-sync 1.12.0",
|
|
||||||
"ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethkey 0.4.0",
|
"ethkey 0.4.0",
|
||||||
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -1502,7 +1496,6 @@ dependencies = [
|
|||||||
"parity-runtime 0.1.0",
|
"parity-runtime 0.1.0",
|
||||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"registrar 0.0.1",
|
|
||||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -3085,9 +3078,11 @@ dependencies = [
|
|||||||
"dir 0.1.2",
|
"dir 0.1.2",
|
||||||
"docopt 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"docopt 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"engine 0.1.0",
|
"engine 0.1.0",
|
||||||
|
"ethabi 9.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethcore 1.12.0",
|
"ethcore 1.12.0",
|
||||||
"ethcore-accounts 0.1.0",
|
"ethcore-accounts 0.1.0",
|
||||||
"ethcore-blockchain 0.1.0",
|
"ethcore-blockchain 0.1.0",
|
||||||
|
"ethcore-call-contract 0.1.0",
|
||||||
"ethcore-db 0.1.0",
|
"ethcore-db 0.1.0",
|
||||||
"ethcore-io 1.12.0",
|
"ethcore-io 1.12.0",
|
||||||
"ethcore-light 1.12.0",
|
"ethcore-light 1.12.0",
|
||||||
|
@ -18,9 +18,11 @@ ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
|
|||||||
dir = { path = "util/dir" }
|
dir = { path = "util/dir" }
|
||||||
docopt = "1.0"
|
docopt = "1.0"
|
||||||
engine = { path = "ethcore/engine" }
|
engine = { path = "ethcore/engine" }
|
||||||
|
ethabi = { version = "9.0.1", optional = true }
|
||||||
ethcore = { path = "ethcore", features = ["parity"] }
|
ethcore = { path = "ethcore", features = ["parity"] }
|
||||||
ethcore-accounts = { path = "accounts", optional = true }
|
ethcore-accounts = { path = "accounts", optional = true }
|
||||||
ethcore-blockchain = { path = "ethcore/blockchain" }
|
ethcore-blockchain = { path = "ethcore/blockchain" }
|
||||||
|
ethcore-call-contract = { path = "ethcore/call-contract", optional = true }
|
||||||
ethcore-db = { path = "ethcore/db" }
|
ethcore-db = { path = "ethcore/db" }
|
||||||
ethcore-io = { path = "util/io" }
|
ethcore-io = { path = "util/io" }
|
||||||
ethcore-light = { path = "ethcore/light" }
|
ethcore-light = { path = "ethcore/light" }
|
||||||
@ -97,7 +99,7 @@ test-heavy = ["ethcore/test-heavy"]
|
|||||||
evm-debug = ["ethcore/evm-debug"]
|
evm-debug = ["ethcore/evm-debug"]
|
||||||
evm-debug-tests = ["ethcore/evm-debug-tests"]
|
evm-debug-tests = ["ethcore/evm-debug-tests"]
|
||||||
slow-blocks = ["ethcore/slow-blocks"]
|
slow-blocks = ["ethcore/slow-blocks"]
|
||||||
secretstore = ["ethcore-secretstore", "ethcore-secretstore/accounts"]
|
secretstore = ["ethcore-secretstore", "accounts", "ethabi", "ethcore-call-contract"]
|
||||||
final = ["parity-version/final"]
|
final = ["parity-version/final"]
|
||||||
deadlock_detection = ["parking_lot/deadlock_detection"]
|
deadlock_detection = ["parking_lot/deadlock_detection"]
|
||||||
# to create a memory profile (requires nightly rust), use e.g.
|
# to create a memory profile (requires nightly rust), use e.g.
|
||||||
|
@ -86,6 +86,12 @@ extern crate ethcore_accounts as accounts;
|
|||||||
#[cfg(feature = "secretstore")]
|
#[cfg(feature = "secretstore")]
|
||||||
extern crate ethcore_secretstore;
|
extern crate ethcore_secretstore;
|
||||||
|
|
||||||
|
#[cfg(feature = "secretstore")]
|
||||||
|
extern crate ethabi;
|
||||||
|
|
||||||
|
#[cfg(feature = "secretstore")]
|
||||||
|
extern crate ethcore_call_contract as call_contract;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate pretty_assertions;
|
extern crate pretty_assertions;
|
||||||
|
246
parity/secretstore/blockchain.rs
Normal file
246
parity/secretstore/blockchain.rs
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! SecretStoreChain implementation with information about blockchain, retrieved from the client
|
||||||
|
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
use ethereum_types::{H256, Address};
|
||||||
|
use parking_lot::RwLock;
|
||||||
|
use types::{
|
||||||
|
ids::BlockId as EthcoreBlockId,
|
||||||
|
transaction::{Transaction, SignedTransaction, Action},
|
||||||
|
chain_notify::NewBlocks,
|
||||||
|
tree_route::TreeRoute,
|
||||||
|
filter::Filter as BlockchainFilter,
|
||||||
|
log_entry::LocalizedLogEntry,
|
||||||
|
};
|
||||||
|
use ethcore::client::Client;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use ethabi::RawLog;
|
||||||
|
use client_traits::BlockChainClient;
|
||||||
|
use call_contract::CallContract;
|
||||||
|
use client_traits::{ChainInfo, Nonce, ChainNotify};
|
||||||
|
use ethcore::miner::{Miner, MinerService};
|
||||||
|
use parity_crypto::publickey::Error as EthKeyError;
|
||||||
|
use sync::SyncProvider;
|
||||||
|
use registrar::RegistrarClient;
|
||||||
|
use ethcore_secretstore::{BlockId, BlockNumber, SecretStoreChain, NewBlocksNotify, SigningKeyPair, ContractAddress, Filter};
|
||||||
|
|
||||||
|
// TODO: Instead of a constant, make this based on consensus finality.
|
||||||
|
/// Number of confirmations required before request can be processed.
|
||||||
|
const REQUEST_CONFIRMATIONS_REQUIRED: u64 = 3;
|
||||||
|
|
||||||
|
fn into_ethcore_block_id(id: BlockId) -> EthcoreBlockId {
|
||||||
|
match id {
|
||||||
|
BlockId::Hash(hash) => EthcoreBlockId::Hash(hash),
|
||||||
|
BlockId::Number(number) => EthcoreBlockId::Number(number),
|
||||||
|
BlockId::Earliest => EthcoreBlockId::Earliest,
|
||||||
|
BlockId::Latest => EthcoreBlockId::Latest,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// SecretStore blockchain implementation (client's wrapper)
|
||||||
|
/// This implementation is trusted, when underlying client is synced and chain's security level is full
|
||||||
|
/// This trust is guaranteed by return result in get_trusted method (if it's not trusted, None is returned)
|
||||||
|
pub struct TrustedClient {
|
||||||
|
/// This key server node key pair.
|
||||||
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
|
/// Blockchain client.
|
||||||
|
client: Weak<Client>,
|
||||||
|
/// Sync provider.
|
||||||
|
sync: Weak<dyn SyncProvider>,
|
||||||
|
/// Miner service.
|
||||||
|
miner: Weak<Miner>,
|
||||||
|
/// Chain new blocks listeners
|
||||||
|
listeners: RwLock<Vec<Weak<dyn NewBlocksNotify>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrustedClient {
|
||||||
|
/// Create new trusted client.
|
||||||
|
pub fn new(self_key_pair: Arc<dyn SigningKeyPair>, client: Arc<Client>, sync: Arc<dyn SyncProvider>, miner: Arc<Miner>) -> Arc<Self> {
|
||||||
|
let trusted_client = Arc::new(TrustedClient {
|
||||||
|
self_key_pair,
|
||||||
|
client: Arc::downgrade(&client),
|
||||||
|
sync: Arc::downgrade(&sync),
|
||||||
|
miner: Arc::downgrade(&miner),
|
||||||
|
listeners: RwLock::default(),
|
||||||
|
});
|
||||||
|
client.add_notify(trusted_client.clone());
|
||||||
|
trusted_client
|
||||||
|
}
|
||||||
|
|
||||||
|
fn notify_listeners(&self, new_enacted_len: usize) {
|
||||||
|
for listener_pointer in self.listeners.read().iter() {
|
||||||
|
if let Some(listener) = listener_pointer.upgrade() {
|
||||||
|
listener.new_blocks(new_enacted_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get 'trusted' `Client` reference only if it is synchronized && trusted.
|
||||||
|
fn get_trusted(&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.is_major_syncing();
|
||||||
|
let is_trusted = client.chain_info().security_level().is_full();
|
||||||
|
match is_synced && is_trusted {
|
||||||
|
true => Some(client),
|
||||||
|
false => None,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tree_route(&self, from: &H256, to: &H256) -> Option<TreeRoute> {
|
||||||
|
if let Some(client) = self.get_trusted() {
|
||||||
|
client.tree_route(from, to)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn logs(&self, filter: BlockchainFilter) -> Option<Vec<LocalizedLogEntry>> {
|
||||||
|
if let Some(client) = self.get_trusted() {
|
||||||
|
client.logs(filter).ok()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SecretStoreChain for TrustedClient {
|
||||||
|
fn add_listener(&self, target: Arc<dyn NewBlocksNotify>) {
|
||||||
|
self.listeners.write().push(Arc::downgrade(&target));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_trusted(&self) -> bool {
|
||||||
|
self.get_trusted().is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn transact_contract(&self, contract: Address, tx_data: Bytes) -> Result<(), EthKeyError> {
|
||||||
|
let client = self.client.upgrade().ok_or_else(|| EthKeyError::Custom("cannot submit tx when client is offline".into()))?;
|
||||||
|
let miner = self.miner.upgrade().ok_or_else(|| EthKeyError::Custom("cannot submit tx when miner is offline".into()))?;
|
||||||
|
let engine = client.engine();
|
||||||
|
let transaction = Transaction {
|
||||||
|
nonce: client.latest_nonce(&self.self_key_pair.address()),
|
||||||
|
action: Action::Call(contract),
|
||||||
|
gas: miner.authoring_params().gas_range_target.0,
|
||||||
|
gas_price: miner.sensible_gas_price(),
|
||||||
|
value: Default::default(),
|
||||||
|
data: tx_data,
|
||||||
|
};
|
||||||
|
let chain_id = engine.signing_chain_id(&client.latest_env_info());
|
||||||
|
let signature = self.self_key_pair.sign(&transaction.hash(chain_id))?;
|
||||||
|
let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
|
||||||
|
miner.import_own_transaction(&*client, signed.into())
|
||||||
|
.map_err(|e| EthKeyError::Custom(format!("failed to import tx: {}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_contract_address(
|
||||||
|
&self,
|
||||||
|
registry_name: &str,
|
||||||
|
address: &ContractAddress
|
||||||
|
) -> Option<Address> {
|
||||||
|
match *address {
|
||||||
|
ContractAddress::Address(ref address) => Some(address.clone()),
|
||||||
|
ContractAddress::Registry => self.get_trusted().and_then(|client|
|
||||||
|
self.get_confirmed_block_hash()
|
||||||
|
.and_then(|block| {
|
||||||
|
client.get_address(registry_name, EthcoreBlockId::Hash(block))
|
||||||
|
.unwrap_or(None)
|
||||||
|
})
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_contract(&self, block_id: BlockId, contract_address: Address, data: Bytes) -> Result<Bytes, String> {
|
||||||
|
if let Some(client) = self.get_trusted() {
|
||||||
|
client.call_contract(into_ethcore_block_id(block_id), contract_address, data)
|
||||||
|
} else {
|
||||||
|
Err("Calling ACL contract without trusted blockchain client".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_hash(&self, id: BlockId) -> Option<H256> {
|
||||||
|
if let Some(client) = self.get_trusted() {
|
||||||
|
client.block_hash(into_ethcore_block_id(id))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
|
||||||
|
if let Some(client) = self.get_trusted() {
|
||||||
|
client.block_number(into_ethcore_block_id(id))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn retrieve_last_logs(&self, filter: Filter) -> Option<Vec<RawLog>> {
|
||||||
|
let confirmed_block = match self.get_confirmed_block_hash() {
|
||||||
|
Some(confirmed_block) => confirmed_block,
|
||||||
|
None => return None, // no block with enough confirmations
|
||||||
|
};
|
||||||
|
|
||||||
|
let from_block = self.block_hash(filter.from_block).unwrap_or_else(|| confirmed_block);
|
||||||
|
let first_block = match self.tree_route(&from_block, &confirmed_block) {
|
||||||
|
// if we have a route from last_log_block to confirmed_block => search for logs on this route
|
||||||
|
//
|
||||||
|
// potentially this could lead us to reading same logs twice when reorganizing to the fork, which
|
||||||
|
// already has been canonical previosuly
|
||||||
|
// the worst thing that can happen in this case is spending some time reading unneeded data from SS db
|
||||||
|
Some(ref route) if route.index < route.blocks.len() => route.blocks[route.index],
|
||||||
|
// else we care only about confirmed block
|
||||||
|
_ => confirmed_block.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.logs(BlockchainFilter {
|
||||||
|
from_block: EthcoreBlockId::Hash(first_block),
|
||||||
|
to_block: EthcoreBlockId::Hash(confirmed_block),
|
||||||
|
address: filter.address,
|
||||||
|
topics: filter.topics,
|
||||||
|
limit: None,
|
||||||
|
})
|
||||||
|
.map(|blockchain_logs| {
|
||||||
|
blockchain_logs
|
||||||
|
.into_iter()
|
||||||
|
.map(|log| {
|
||||||
|
let raw_log: RawLog = (log.entry.topics.into_iter().map(|t| t.0.into()).collect(), log.entry.data).into();
|
||||||
|
raw_log
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_confirmed_block_hash(&self) -> Option<H256> {
|
||||||
|
self.block_number(BlockId::Latest)
|
||||||
|
.map(|b| b.saturating_sub(REQUEST_CONFIRMATIONS_REQUIRED))
|
||||||
|
.and_then(|b| self.block_hash(BlockId::Number(b)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainNotify for TrustedClient {
|
||||||
|
fn new_blocks(&self, new_blocks: NewBlocks) {
|
||||||
|
if new_blocks.has_more_blocks_to_import { return }
|
||||||
|
if !new_blocks.route.enacted().is_empty() || !new_blocks.route.retracted().is_empty() {
|
||||||
|
let enacted_len = new_blocks.route.enacted().len();
|
||||||
|
self.notify_listeners(enacted_len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,18 +14,18 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use ethcore::client::Client;
|
//! Secret store related components.
|
||||||
use client_traits::BlockChainClient;
|
|
||||||
use common_types::ids::BlockId;
|
|
||||||
use ethereum_types::H256;
|
|
||||||
|
|
||||||
// TODO: Instead of a constant, make this based on consensus finality.
|
mod server;
|
||||||
/// Number of confirmations required before request can be processed.
|
|
||||||
pub const REQUEST_CONFIRMATIONS_REQUIRED: u64 = 3;
|
|
||||||
|
|
||||||
/// Get hash of the last block with at least n confirmations.
|
#[cfg(feature = "secretstore")]
|
||||||
pub fn get_confirmed_block_hash(client: &Client, confirmations: u64) -> Option<H256> {
|
mod blockchain;
|
||||||
client.block_number(BlockId::Latest)
|
|
||||||
.map(|b| b.saturating_sub(confirmations))
|
#[cfg(all(feature = "accounts", feature = "secretstore"))]
|
||||||
.and_then(|b| client.block_hash(BlockId::Number(b)))
|
mod nodekeypair;
|
||||||
}
|
|
||||||
|
pub use self::server::{Configuration, NodeSecretKey, ContractAddress, Dependencies, start};
|
||||||
|
#[cfg(feature = "secretstore")]
|
||||||
|
use self::blockchain::TrustedClient;
|
||||||
|
#[cfg(all(feature = "accounts", feature = "secretstore"))]
|
||||||
|
use self::nodekeypair::KeyStoreNodeKeyPair;
|
59
parity/secretstore/nodekeypair.rs
Normal file
59
parity/secretstore/nodekeypair.rs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Key pair with signing ability
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use accounts::AccountProvider;
|
||||||
|
use ethkey::Password;
|
||||||
|
use parity_crypto::publickey::public_to_address;
|
||||||
|
use ethereum_types::{H256, Address, Public};
|
||||||
|
use parity_crypto::publickey::{Signature, Error as EthKeyError};
|
||||||
|
use ethcore_secretstore::SigningKeyPair;
|
||||||
|
|
||||||
|
pub struct KeyStoreNodeKeyPair {
|
||||||
|
account_provider: Arc<AccountProvider>,
|
||||||
|
address: Address,
|
||||||
|
public: Public,
|
||||||
|
password: Password,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyStoreNodeKeyPair {
|
||||||
|
pub fn new(account_provider: Arc<AccountProvider>, address: Address, password: Password) -> Result<Self, EthKeyError> {
|
||||||
|
let public = account_provider.account_public(address.clone(), &password).map_err(|e| EthKeyError::Custom(format!("{}", e)))?;
|
||||||
|
Ok(KeyStoreNodeKeyPair {
|
||||||
|
account_provider,
|
||||||
|
address,
|
||||||
|
public,
|
||||||
|
password,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SigningKeyPair for KeyStoreNodeKeyPair {
|
||||||
|
fn public(&self) -> &Public {
|
||||||
|
&self.public
|
||||||
|
}
|
||||||
|
|
||||||
|
fn address(&self) -> Address {
|
||||||
|
public_to_address(&self.public)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign(&self, data: &H256) -> Result<Signature, EthKeyError> {
|
||||||
|
self.account_provider.sign(self.address.clone(), Some(self.password.clone()), data.clone())
|
||||||
|
.map_err(|e| EthKeyError::Custom(format!("{}", e)))
|
||||||
|
}
|
||||||
|
}
|
@ -14,6 +14,8 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
//! Secret store server's launcher, contains required configuration parameters and launch method
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use account_utils::AccountProvider;
|
use account_utils::AccountProvider;
|
||||||
@ -125,6 +127,9 @@ mod server {
|
|||||||
use parity_crypto::publickey::KeyPair;
|
use parity_crypto::publickey::KeyPair;
|
||||||
use ansi_term::Colour::{Red, White};
|
use ansi_term::Colour::{Red, White};
|
||||||
use super::{Configuration, Dependencies, NodeSecretKey, ContractAddress, Executor};
|
use super::{Configuration, Dependencies, NodeSecretKey, ContractAddress, Executor};
|
||||||
|
use super::super::TrustedClient;
|
||||||
|
#[cfg(feature = "accounts")]
|
||||||
|
use super::super::KeyStoreNodeKeyPair;
|
||||||
|
|
||||||
fn into_service_contract_address(address: ContractAddress) -> ethcore_secretstore::ContractAddress {
|
fn into_service_contract_address(address: ContractAddress) -> ethcore_secretstore::ContractAddress {
|
||||||
match address {
|
match address {
|
||||||
@ -141,7 +146,7 @@ mod server {
|
|||||||
impl KeyServer {
|
impl KeyServer {
|
||||||
/// Create new key server
|
/// Create new key server
|
||||||
pub fn new(mut conf: Configuration, deps: Dependencies, executor: Executor) -> Result<Self, String> {
|
pub fn new(mut conf: Configuration, deps: Dependencies, executor: Executor) -> Result<Self, String> {
|
||||||
let self_secret: Arc<dyn ethcore_secretstore::NodeKeyPair> = match conf.self_secret.take() {
|
let self_secret: Arc<dyn ethcore_secretstore::SigningKeyPair> = match conf.self_secret.take() {
|
||||||
Some(NodeSecretKey::Plain(secret)) => Arc::new(ethcore_secretstore::PlainNodeKeyPair::new(
|
Some(NodeSecretKey::Plain(secret)) => Arc::new(ethcore_secretstore::PlainNodeKeyPair::new(
|
||||||
KeyPair::from_secret(secret).map_err(|e| format!("invalid secret: {}", e))?)),
|
KeyPair::from_secret(secret).map_err(|e| format!("invalid secret: {}", e))?)),
|
||||||
#[cfg(feature = "accounts")]
|
#[cfg(feature = "accounts")]
|
||||||
@ -160,7 +165,7 @@ mod server {
|
|||||||
let password = deps.accounts_passwords.iter()
|
let password = deps.accounts_passwords.iter()
|
||||||
.find(|p| deps.account_provider.sign(account.clone(), Some((*p).clone()), Default::default()).is_ok())
|
.find(|p| deps.account_provider.sign(account.clone(), Some((*p).clone()), Default::default()).is_ok())
|
||||||
.ok_or_else(|| format!("No valid password for the secret store node account {}", account))?;
|
.ok_or_else(|| format!("No valid password for the secret store node account {}", account))?;
|
||||||
Arc::new(ethcore_secretstore::KeyStoreNodeKeyPair::new(deps.account_provider, account, password.clone())
|
Arc::new(KeyStoreNodeKeyPair::new(deps.account_provider, account, password.clone())
|
||||||
.map_err(|e| format!("{}", e))?)
|
.map_err(|e| format!("{}", e))?)
|
||||||
},
|
},
|
||||||
None => return Err("self secret is required when using secretstore".into()),
|
None => return Err("self secret is required when using secretstore".into()),
|
||||||
@ -203,7 +208,8 @@ mod server {
|
|||||||
cconf.cluster_config.nodes.insert(self_secret.public().clone(), cconf.cluster_config.listener_address.clone());
|
cconf.cluster_config.nodes.insert(self_secret.public().clone(), cconf.cluster_config.listener_address.clone());
|
||||||
|
|
||||||
let db = ethcore_secretstore::open_secretstore_db(&conf.data_path)?;
|
let db = ethcore_secretstore::open_secretstore_db(&conf.data_path)?;
|
||||||
let key_server = ethcore_secretstore::start(deps.client, deps.sync, deps.miner, self_secret, cconf, db, executor)
|
let trusted_client = TrustedClient::new(self_secret.clone(), deps.client, deps.sync, deps.miner);
|
||||||
|
let key_server = ethcore_secretstore::start(trusted_client, self_secret, cconf, db, executor)
|
||||||
.map_err(|e| format!("Error starting KeyServer {}: {}", key_server_name, e))?;
|
.map_err(|e| format!("Error starting KeyServer {}: {}", key_server_name, e))?;
|
||||||
|
|
||||||
Ok(KeyServer {
|
Ok(KeyServer {
|
@ -7,15 +7,9 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
byteorder = "1.0"
|
byteorder = "1.0"
|
||||||
client-traits = { path = "../ethcore/client-traits" }
|
|
||||||
common-types = { path = "../ethcore/types" }
|
|
||||||
ethabi = "9.0.1"
|
ethabi = "9.0.1"
|
||||||
ethabi-contract = "9.0.0"
|
ethabi-contract = "9.0.0"
|
||||||
ethabi-derive = "9.0.1"
|
ethabi-derive = "9.0.1"
|
||||||
ethcore = { path = "../ethcore" }
|
|
||||||
ethcore-accounts = { path = "../accounts", optional = true}
|
|
||||||
ethcore-call-contract = { path = "../ethcore/call-contract" }
|
|
||||||
ethcore-sync = { path = "../ethcore/sync" }
|
|
||||||
ethereum-types = "0.8.0"
|
ethereum-types = "0.8.0"
|
||||||
ethkey = { path = "../accounts/ethkey", optional = true }
|
ethkey = { path = "../accounts/ethkey", optional = true }
|
||||||
futures = "0.1"
|
futures = "0.1"
|
||||||
@ -30,7 +24,6 @@ parity-crypto = { version = "0.4.2", features = ["publickey"] }
|
|||||||
parity-runtime = { path = "../util/runtime" }
|
parity-runtime = { path = "../util/runtime" }
|
||||||
parking_lot = "0.9"
|
parking_lot = "0.9"
|
||||||
percent-encoding = "2.1.0"
|
percent-encoding = "2.1.0"
|
||||||
registrar = { path = "../util/registrar" }
|
|
||||||
rustc-hex = "1.0"
|
rustc-hex = "1.0"
|
||||||
serde = "1.0"
|
serde = "1.0"
|
||||||
serde_derive = "1.0"
|
serde_derive = "1.0"
|
||||||
@ -44,10 +37,5 @@ jsonrpc-server-utils = "14.0.3"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
ethkey = { path = "../accounts/ethkey" }
|
|
||||||
ethcore = { path = "../ethcore", features = ["test-helpers"] }
|
|
||||||
tempdir = "0.3"
|
tempdir = "0.3"
|
||||||
kvdb-rocksdb = "0.3.0"
|
kvdb-rocksdb = "0.3.0"
|
||||||
|
|
||||||
[features]
|
|
||||||
accounts = ["ethcore-accounts", "ethkey"]
|
|
||||||
|
@ -16,17 +16,11 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use common_types::{
|
|
||||||
chain_notify::NewBlocks,
|
|
||||||
ids::BlockId
|
|
||||||
};
|
|
||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use call_contract::CallContract;
|
|
||||||
use client_traits::ChainNotify;
|
|
||||||
use ethereum_types::Address;
|
use ethereum_types::Address;
|
||||||
use ethabi::FunctionOutputDecoder;
|
use ethabi::FunctionOutputDecoder;
|
||||||
use trusted_client::TrustedClient;
|
use blockchain::{SecretStoreChain, NewBlocksNotify, ContractAddress, BlockId};
|
||||||
use types::{Error, ServerKeyId, ContractAddress};
|
use types::{Error, ServerKeyId};
|
||||||
|
|
||||||
use_contract!(acl_storage, "res/acl_storage.json");
|
use_contract!(acl_storage, "res/acl_storage.json");
|
||||||
|
|
||||||
@ -47,7 +41,7 @@ pub struct OnChainAclStorage {
|
|||||||
/// Cached on-chain ACL storage contract.
|
/// Cached on-chain ACL storage contract.
|
||||||
struct CachedContract {
|
struct CachedContract {
|
||||||
/// Blockchain client.
|
/// Blockchain client.
|
||||||
client: TrustedClient,
|
client: Arc<dyn SecretStoreChain>,
|
||||||
/// Contract address source.
|
/// Contract address source.
|
||||||
address_source: ContractAddress,
|
address_source: ContractAddress,
|
||||||
/// Current contract address.
|
/// Current contract address.
|
||||||
@ -61,14 +55,11 @@ pub struct DummyAclStorage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OnChainAclStorage {
|
impl OnChainAclStorage {
|
||||||
pub fn new(trusted_client: TrustedClient, address_source: ContractAddress) -> Result<Arc<Self>, Error> {
|
pub fn new(trusted_client: Arc<dyn SecretStoreChain>, address_source: ContractAddress) -> Result<Arc<Self>, Error> {
|
||||||
let client = trusted_client.get_untrusted();
|
|
||||||
let acl_storage = Arc::new(OnChainAclStorage {
|
let acl_storage = Arc::new(OnChainAclStorage {
|
||||||
contract: Mutex::new(CachedContract::new(trusted_client, address_source)),
|
contract: Mutex::new(CachedContract::new(trusted_client.clone(), address_source)),
|
||||||
});
|
});
|
||||||
client
|
trusted_client.add_listener(acl_storage.clone());
|
||||||
.ok_or_else(|| Error::Internal("Constructing OnChainAclStorage without active Client".into()))?
|
|
||||||
.add_notify(acl_storage.clone());
|
|
||||||
Ok(acl_storage)
|
Ok(acl_storage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -79,17 +70,14 @@ impl AclStorage for OnChainAclStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChainNotify for OnChainAclStorage {
|
impl NewBlocksNotify for OnChainAclStorage {
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, _new_enacted_len: usize) {
|
||||||
if new_blocks.has_more_blocks_to_import { return }
|
|
||||||
if !new_blocks.route.enacted().is_empty() || !new_blocks.route.retracted().is_empty() {
|
|
||||||
self.contract.lock().update_contract_address()
|
self.contract.lock().update_contract_address()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl CachedContract {
|
impl CachedContract {
|
||||||
pub fn new(client: TrustedClient, address_source: ContractAddress) -> Self {
|
pub fn new(client: Arc<dyn SecretStoreChain>, address_source: ContractAddress) -> Self {
|
||||||
let mut contract = CachedContract {
|
let mut contract = CachedContract {
|
||||||
client,
|
client,
|
||||||
address_source,
|
address_source,
|
||||||
@ -113,12 +101,12 @@ impl CachedContract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(&mut self, requester: Address, document: &ServerKeyId) -> Result<bool, Error> {
|
pub fn check(&mut self, requester: Address, document: &ServerKeyId) -> Result<bool, Error> {
|
||||||
if let Some(client) = self.client.get() {
|
if self.client.is_trusted() {
|
||||||
// call contract to check accesss
|
// call contract to check accesss
|
||||||
match self.contract_address {
|
match self.contract_address {
|
||||||
Some(contract_address) => {
|
Some(contract_address) => {
|
||||||
let (encoded, decoder) = acl_storage::functions::check_permissions::call(requester, document.clone());
|
let (encoded, decoder) = acl_storage::functions::check_permissions::call(requester, document.clone());
|
||||||
let d = client.call_contract(BlockId::Latest, contract_address, encoded)
|
let d = self.client.call_contract(BlockId::Latest, contract_address, encoded)
|
||||||
.map_err(|e| Error::Internal(format!("ACL checker call error: {}", e.to_string())))?;
|
.map_err(|e| Error::Internal(format!("ACL checker call error: {}", e.to_string())))?;
|
||||||
decoder.decode(&d)
|
decoder.decode(&d)
|
||||||
.map_err(|e| Error::Internal(format!("ACL checker call error: {}", e.to_string())))
|
.map_err(|e| Error::Internal(format!("ACL checker call error: {}", e.to_string())))
|
||||||
|
119
secret-store/src/blockchain.rs
Normal file
119
secret-store/src/blockchain.rs
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
||||||
|
// This file is part of Parity Ethereum.
|
||||||
|
|
||||||
|
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
use bytes::Bytes;
|
||||||
|
use ethereum_types::{H256, Address, Public};
|
||||||
|
use ethabi::RawLog;
|
||||||
|
use crypto::publickey::{Signature, Error as EthKeyError};
|
||||||
|
|
||||||
|
/// Type for block number.
|
||||||
|
/// Duplicated from ethcore types
|
||||||
|
pub type BlockNumber = u64;
|
||||||
|
|
||||||
|
/// Uniquely identifies block.
|
||||||
|
/// Duplicated from ethcore types
|
||||||
|
#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)]
|
||||||
|
pub enum BlockId {
|
||||||
|
/// Block's sha3.
|
||||||
|
/// Querying by hash is always faster.
|
||||||
|
Hash(H256),
|
||||||
|
/// Block number within canon blockchain.
|
||||||
|
Number(BlockNumber),
|
||||||
|
/// Earliest block (genesis).
|
||||||
|
Earliest,
|
||||||
|
/// Latest mined block.
|
||||||
|
Latest,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contract address.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub enum ContractAddress {
|
||||||
|
/// Address is read from registry.
|
||||||
|
Registry,
|
||||||
|
/// Address is specified.
|
||||||
|
Address(ethereum_types::Address),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Key pair with signing ability.
|
||||||
|
pub trait SigningKeyPair: Send + Sync {
|
||||||
|
/// Public portion of key.
|
||||||
|
fn public(&self) -> &Public;
|
||||||
|
/// Address of key owner.
|
||||||
|
fn address(&self) -> Address;
|
||||||
|
/// Sign data with the key.
|
||||||
|
fn sign(&self, data: &H256) -> Result<Signature, EthKeyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Wrapps client ChainNotify in order to send signal about new blocks
|
||||||
|
pub trait NewBlocksNotify: Send + Sync {
|
||||||
|
/// Fires when chain has new blocks.
|
||||||
|
/// Sends this signal only, if contracts' update required
|
||||||
|
fn new_blocks(&self, _new_enacted_len: usize) {
|
||||||
|
// does nothing by default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blockchain logs Filter.
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct Filter {
|
||||||
|
/// Blockchain will be searched from this block.
|
||||||
|
pub from_block: BlockId,
|
||||||
|
|
||||||
|
/// Search addresses.
|
||||||
|
///
|
||||||
|
/// If None, match all.
|
||||||
|
/// If specified, log must be produced by one of these addresses.
|
||||||
|
pub address: Option<Vec<Address>>,
|
||||||
|
|
||||||
|
/// Search topics.
|
||||||
|
///
|
||||||
|
/// If None, match all.
|
||||||
|
/// If specified, log must contain one of these topics.
|
||||||
|
pub topics: Vec<Option<Vec<H256>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Blockchain representation for Secret Store
|
||||||
|
pub trait SecretStoreChain: Send + Sync + 'static {
|
||||||
|
/// Adds listener for chain's NewBlocks event
|
||||||
|
fn add_listener(&self, target: Arc<dyn NewBlocksNotify>);
|
||||||
|
|
||||||
|
/// Check if the underlying chain is in the trusted state
|
||||||
|
fn is_trusted(&self) -> bool;
|
||||||
|
|
||||||
|
/// Transact contract.
|
||||||
|
fn transact_contract(&self, contract: Address, tx_data: Bytes) -> Result<(), EthKeyError>;
|
||||||
|
|
||||||
|
/// Read contract address. If address source is registry, address only returned if current client state is
|
||||||
|
/// trusted. Address from registry is read from registry from block latest block with
|
||||||
|
/// REQUEST_CONFIRMATIONS_REQUIRED confirmations.
|
||||||
|
fn read_contract_address(&self, registry_name: &str, address: &ContractAddress) -> Option<Address>;
|
||||||
|
|
||||||
|
/// Call contract in the blockchain
|
||||||
|
fn call_contract(&self, block_id: BlockId, contract_address: Address, data: Bytes) -> Result<Bytes, String>;
|
||||||
|
|
||||||
|
/// Returns blockhash for block id
|
||||||
|
fn block_hash(&self, id: BlockId) -> Option<H256>;
|
||||||
|
|
||||||
|
/// Returns block number for block id
|
||||||
|
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
|
||||||
|
|
||||||
|
/// Retrieve last blockchain logs for the filter
|
||||||
|
fn retrieve_last_logs(&self, filter: Filter) -> Option<Vec<RawLog>>;
|
||||||
|
|
||||||
|
/// Get hash of the last block with predefined number of confirmations (depends on the chain).
|
||||||
|
fn get_confirmed_block_hash(&self) -> Option<H256>;
|
||||||
|
}
|
@ -24,8 +24,9 @@ use parity_runtime::Executor;
|
|||||||
use super::acl_storage::AclStorage;
|
use super::acl_storage::AclStorage;
|
||||||
use super::key_storage::KeyStorage;
|
use super::key_storage::KeyStorage;
|
||||||
use super::key_server_set::KeyServerSet;
|
use super::key_server_set::KeyServerSet;
|
||||||
|
use blockchain::SigningKeyPair;
|
||||||
use key_server_cluster::{math, new_network_cluster, ClusterSession, WaitableSession};
|
use key_server_cluster::{math, new_network_cluster, ClusterSession, WaitableSession};
|
||||||
use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer, NodeKeyPair};
|
use traits::{AdminSessionsServer, ServerKeyGenerator, DocumentKeyServer, MessageSigner, KeyServer};
|
||||||
use types::{Error, Public, RequestSignature, Requester, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow,
|
use types::{Error, Public, RequestSignature, Requester, ServerKeyId, EncryptedDocumentKey, EncryptedDocumentKeyShadow,
|
||||||
ClusterConfiguration, MessageHash, EncryptedMessageSignature, NodeId};
|
ClusterConfiguration, MessageHash, EncryptedMessageSignature, NodeId};
|
||||||
use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration, NetConnectionsManagerConfig};
|
use key_server_cluster::{ClusterClient, ClusterConfiguration as NetClusterConfiguration, NetConnectionsManagerConfig};
|
||||||
@ -42,7 +43,7 @@ pub struct KeyServerCore {
|
|||||||
|
|
||||||
impl KeyServerImpl {
|
impl KeyServerImpl {
|
||||||
/// Create new key server instance
|
/// Create new key server instance
|
||||||
pub fn new(config: &ClusterConfiguration, key_server_set: Arc<dyn KeyServerSet>, self_key_pair: Arc<dyn NodeKeyPair>,
|
pub fn new(config: &ClusterConfiguration, key_server_set: Arc<dyn KeyServerSet>, self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
acl_storage: Arc<dyn AclStorage>, key_storage: Arc<dyn KeyStorage>, executor: Executor) -> Result<Self, Error>
|
acl_storage: Arc<dyn AclStorage>, key_storage: Arc<dyn KeyStorage>, executor: Executor) -> Result<Self, Error>
|
||||||
{
|
{
|
||||||
Ok(KeyServerImpl {
|
Ok(KeyServerImpl {
|
||||||
@ -269,7 +270,7 @@ impl MessageSigner for KeyServerImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl KeyServerCore {
|
impl KeyServerCore {
|
||||||
pub fn new(config: &ClusterConfiguration, key_server_set: Arc<dyn KeyServerSet>, self_key_pair: Arc<dyn NodeKeyPair>,
|
pub fn new(config: &ClusterConfiguration, key_server_set: Arc<dyn KeyServerSet>, self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
acl_storage: Arc<dyn AclStorage>, key_storage: Arc<dyn KeyStorage>, executor: Executor) -> Result<Self, Error>
|
acl_storage: Arc<dyn AclStorage>, key_storage: Arc<dyn KeyStorage>, executor: Executor) -> Result<Self, Error>
|
||||||
{
|
{
|
||||||
let cconfig = NetClusterConfiguration {
|
let cconfig = NetClusterConfiguration {
|
||||||
|
@ -1051,7 +1051,8 @@ pub mod tests {
|
|||||||
use std::collections::{VecDeque, BTreeMap, BTreeSet};
|
use std::collections::{VecDeque, BTreeMap, BTreeSet};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use crypto::publickey::{Random, Generator, Public, Signature, KeyPair, sign};
|
use crypto::publickey::{Random, Generator, Public, Signature, KeyPair, sign};
|
||||||
use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, NodeKeyPair, PlainNodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
use key_server_cluster::{NodeId, SessionId, Error, KeyStorage, PlainNodeKeyPair};
|
||||||
use key_server_cluster::cluster_sessions::ClusterSession;
|
use key_server_cluster::cluster_sessions::ClusterSession;
|
||||||
use key_server_cluster::cluster::tests::MessageLoop as ClusterMessageLoop;
|
use key_server_cluster::cluster::tests::MessageLoop as ClusterMessageLoop;
|
||||||
use key_server_cluster::generation_session::tests::{MessageLoop as GenerationMessageLoop};
|
use key_server_cluster::generation_session::tests::{MessageLoop as GenerationMessageLoop};
|
||||||
|
@ -889,7 +889,8 @@ impl SessionTransport for IsolatedSessionTransport {
|
|||||||
pub mod tests {
|
pub mod tests {
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use crypto::publickey::{Random, Generator, Public};
|
use crypto::publickey::{Random, Generator, Public};
|
||||||
use key_server_cluster::{NodeId, Error, KeyStorage, NodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
use key_server_cluster::{NodeId, Error, KeyStorage};
|
||||||
use key_server_cluster::cluster::tests::MessageLoop as ClusterMessageLoop;
|
use key_server_cluster::cluster::tests::MessageLoop as ClusterMessageLoop;
|
||||||
use key_server_cluster::servers_set_change_session::tests::{MessageLoop, AdminSessionAdapter, generate_key};
|
use key_server_cluster::servers_set_change_session::tests::{MessageLoop, AdminSessionAdapter, generate_key};
|
||||||
use key_server_cluster::admin_sessions::ShareChangeSessionMeta;
|
use key_server_cluster::admin_sessions::ShareChangeSessionMeta;
|
||||||
|
@ -20,7 +20,8 @@ use parking_lot::RwLock;
|
|||||||
use crypto::publickey::{Public, Signature, Random, Generator};
|
use crypto::publickey::{Public, Signature, Random, Generator};
|
||||||
use ethereum_types::{Address, H256};
|
use ethereum_types::{Address, H256};
|
||||||
use parity_runtime::Executor;
|
use parity_runtime::Executor;
|
||||||
use key_server_cluster::{Error, NodeId, SessionId, Requester, AclStorage, KeyStorage, KeyServerSet, NodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
use key_server_cluster::{Error, NodeId, SessionId, Requester, AclStorage, KeyStorage, KeyServerSet};
|
||||||
use key_server_cluster::cluster_sessions::{WaitableSession, ClusterSession, AdminSession, ClusterSessions,
|
use key_server_cluster::cluster_sessions::{WaitableSession, ClusterSession, AdminSession, ClusterSessions,
|
||||||
SessionIdWithSubSession, ClusterSessionsContainer, SERVERS_SET_CHANGE_SESSION_ID, create_cluster_view,
|
SessionIdWithSubSession, ClusterSessionsContainer, SERVERS_SET_CHANGE_SESSION_ID, create_cluster_view,
|
||||||
AdminSessionCreationData, ClusterSessionsListener};
|
AdminSessionCreationData, ClusterSessionsListener};
|
||||||
@ -143,7 +144,7 @@ pub trait Cluster: Send + Sync {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ClusterConfiguration {
|
pub struct ClusterConfiguration {
|
||||||
/// KeyPair this node holds.
|
/// KeyPair this node holds.
|
||||||
pub self_key_pair: Arc<dyn NodeKeyPair>,
|
pub self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
/// Cluster nodes set.
|
/// Cluster nodes set.
|
||||||
pub key_server_set: Arc<dyn KeyServerSet>,
|
pub key_server_set: Arc<dyn KeyServerSet>,
|
||||||
/// Reference to key storage
|
/// Reference to key storage
|
||||||
@ -173,7 +174,7 @@ pub struct ClusterView {
|
|||||||
configured_nodes_count: usize,
|
configured_nodes_count: usize,
|
||||||
connected_nodes: BTreeSet<NodeId>,
|
connected_nodes: BTreeSet<NodeId>,
|
||||||
connections: Arc<dyn ConnectionProvider>,
|
connections: Arc<dyn ConnectionProvider>,
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cross-thread shareable cluster data.
|
/// Cross-thread shareable cluster data.
|
||||||
@ -181,7 +182,7 @@ pub struct ClusterData<C: ConnectionManager> {
|
|||||||
/// Cluster configuration.
|
/// Cluster configuration.
|
||||||
pub config: ClusterConfiguration,
|
pub config: ClusterConfiguration,
|
||||||
/// KeyPair this node holds.
|
/// KeyPair this node holds.
|
||||||
pub self_key_pair: Arc<dyn NodeKeyPair>,
|
pub self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
/// Connections data.
|
/// Connections data.
|
||||||
pub connections: C,
|
pub connections: C,
|
||||||
/// Active sessions data.
|
/// Active sessions data.
|
||||||
@ -311,7 +312,7 @@ impl<C: ConnectionManager> ClusterCore<C> {
|
|||||||
|
|
||||||
impl ClusterView {
|
impl ClusterView {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
connections: Arc<dyn ConnectionProvider>,
|
connections: Arc<dyn ConnectionProvider>,
|
||||||
nodes: BTreeSet<NodeId>,
|
nodes: BTreeSet<NodeId>,
|
||||||
configured_nodes_count: usize
|
configured_nodes_count: usize
|
||||||
@ -597,7 +598,7 @@ pub struct ServersSetChangeParams {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_servers_set_change_session(
|
pub fn new_servers_set_change_session(
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
sessions: &ClusterSessions,
|
sessions: &ClusterSessions,
|
||||||
connections: Arc<dyn ConnectionProvider>,
|
connections: Arc<dyn ConnectionProvider>,
|
||||||
servers_set_change_creator_connector: Arc<dyn ServersSetChangeSessionCreatorConnector>,
|
servers_set_change_creator_connector: Arc<dyn ServersSetChangeSessionCreatorConnector>,
|
||||||
@ -656,8 +657,9 @@ pub mod tests {
|
|||||||
use parking_lot::{Mutex, RwLock};
|
use parking_lot::{Mutex, RwLock};
|
||||||
use ethereum_types::{Address, H256};
|
use ethereum_types::{Address, H256};
|
||||||
use crypto::publickey::{Random, Generator, Public, Signature, sign};
|
use crypto::publickey::{Random, Generator, Public, Signature, sign};
|
||||||
|
use blockchain::SigningKeyPair;
|
||||||
use key_server_cluster::{NodeId, SessionId, Requester, Error, DummyAclStorage, DummyKeyStorage,
|
use key_server_cluster::{NodeId, SessionId, Requester, Error, DummyAclStorage, DummyKeyStorage,
|
||||||
MapKeyServerSet, PlainNodeKeyPair, NodeKeyPair};
|
MapKeyServerSet, PlainNodeKeyPair};
|
||||||
use key_server_cluster::message::Message;
|
use key_server_cluster::message::Message;
|
||||||
use key_server_cluster::cluster::{new_test_cluster, Cluster, ClusterCore, ClusterConfiguration, ClusterClient};
|
use key_server_cluster::cluster::{new_test_cluster, Cluster, ClusterCore, ClusterConfiguration, ClusterClient};
|
||||||
use key_server_cluster::cluster_connections::ConnectionManager;
|
use key_server_cluster::cluster_connections::ConnectionManager;
|
||||||
|
@ -27,7 +27,8 @@ use tokio::timer::{Interval, timeout::Error as TimeoutError};
|
|||||||
use tokio_io::IoFuture;
|
use tokio_io::IoFuture;
|
||||||
use crypto::publickey::KeyPair;
|
use crypto::publickey::KeyPair;
|
||||||
use parity_runtime::Executor;
|
use parity_runtime::Executor;
|
||||||
use key_server_cluster::{Error, NodeId, ClusterConfiguration, NodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
use key_server_cluster::{Error, NodeId, ClusterConfiguration};
|
||||||
use key_server_cluster::cluster_connections::{ConnectionProvider, Connection, ConnectionManager};
|
use key_server_cluster::cluster_connections::{ConnectionProvider, Connection, ConnectionManager};
|
||||||
use key_server_cluster::connection_trigger::{Maintain, ConnectionTrigger};
|
use key_server_cluster::connection_trigger::{Maintain, ConnectionTrigger};
|
||||||
use key_server_cluster::cluster_message_processor::MessageProcessor;
|
use key_server_cluster::cluster_message_processor::MessageProcessor;
|
||||||
@ -79,7 +80,7 @@ struct NetConnectionsData {
|
|||||||
/// Reference to tokio task executor.
|
/// Reference to tokio task executor.
|
||||||
executor: Executor,
|
executor: Executor,
|
||||||
/// Key pair of this node.
|
/// Key pair of this node.
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
/// Network messages processor.
|
/// Network messages processor.
|
||||||
message_processor: Arc<dyn MessageProcessor>,
|
message_processor: Arc<dyn MessageProcessor>,
|
||||||
/// Connections trigger.
|
/// Connections trigger.
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use key_server_cluster::{Error, NodeId, NodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
use key_server_cluster::{Error, NodeId};
|
||||||
use key_server_cluster::cluster::{ServersSetChangeParams, new_servers_set_change_session};
|
use key_server_cluster::cluster::{ServersSetChangeParams, new_servers_set_change_session};
|
||||||
use key_server_cluster::cluster_sessions::{AdminSession};
|
use key_server_cluster::cluster_sessions::{AdminSession};
|
||||||
use key_server_cluster::cluster_connections::{ConnectionProvider, Connection};
|
use key_server_cluster::cluster_connections::{ConnectionProvider, Connection};
|
||||||
@ -49,7 +50,7 @@ pub trait MessageProcessor: Send + Sync {
|
|||||||
|
|
||||||
/// Bridge between ConnectionManager and ClusterSessions.
|
/// Bridge between ConnectionManager and ClusterSessions.
|
||||||
pub struct SessionsMessageProcessor {
|
pub struct SessionsMessageProcessor {
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
servers_set_change_creator_connector: Arc<dyn ServersSetChangeSessionCreatorConnector>,
|
servers_set_change_creator_connector: Arc<dyn ServersSetChangeSessionCreatorConnector>,
|
||||||
sessions: Arc<ClusterSessions>,
|
sessions: Arc<ClusterSessions>,
|
||||||
connections: Arc<dyn ConnectionProvider>,
|
connections: Arc<dyn ConnectionProvider>,
|
||||||
@ -58,7 +59,7 @@ pub struct SessionsMessageProcessor {
|
|||||||
impl SessionsMessageProcessor {
|
impl SessionsMessageProcessor {
|
||||||
/// Create new instance of SessionsMessageProcessor.
|
/// Create new instance of SessionsMessageProcessor.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
servers_set_change_creator_connector: Arc<dyn ServersSetChangeSessionCreatorConnector>,
|
servers_set_change_creator_connector: Arc<dyn ServersSetChangeSessionCreatorConnector>,
|
||||||
sessions: Arc<ClusterSessions>,
|
sessions: Arc<ClusterSessions>,
|
||||||
connections: Arc<dyn ConnectionProvider>,
|
connections: Arc<dyn ConnectionProvider>,
|
||||||
|
@ -22,7 +22,8 @@ use futures::{oneshot, Oneshot, Complete, Future};
|
|||||||
use parking_lot::{Mutex, RwLock, Condvar};
|
use parking_lot::{Mutex, RwLock, Condvar};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use crypto::publickey::Secret;
|
use crypto::publickey::Secret;
|
||||||
use key_server_cluster::{Error, NodeId, SessionId, NodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
use key_server_cluster::{Error, NodeId, SessionId};
|
||||||
use key_server_cluster::cluster::{Cluster, ClusterConfiguration, ClusterView};
|
use key_server_cluster::cluster::{Cluster, ClusterConfiguration, ClusterView};
|
||||||
use key_server_cluster::cluster_connections::ConnectionProvider;
|
use key_server_cluster::cluster_connections::ConnectionProvider;
|
||||||
use key_server_cluster::connection_trigger::ServersSetChangeSessionCreatorConnector;
|
use key_server_cluster::connection_trigger::ServersSetChangeSessionCreatorConnector;
|
||||||
@ -647,7 +648,7 @@ impl<T> CompletionSignal<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_cluster_view(self_key_pair: Arc<dyn NodeKeyPair>, connections: Arc<dyn ConnectionProvider>, requires_all_connections: bool) -> Result<Arc<dyn Cluster>, Error> {
|
pub fn create_cluster_view(self_key_pair: Arc<dyn SigningKeyPair>, connections: Arc<dyn ConnectionProvider>, requires_all_connections: bool) -> Result<Arc<dyn Cluster>, Error> {
|
||||||
let mut connected_nodes = connections.connected_nodes()?;
|
let mut connected_nodes = connections.connected_nodes()?;
|
||||||
let disconnected_nodes = connections.disconnected_nodes();
|
let disconnected_nodes = connections.disconnected_nodes();
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ use key_server_cluster::cluster_sessions::AdminSession;
|
|||||||
use key_server_cluster::cluster_connections::{Connection};
|
use key_server_cluster::cluster_connections::{Connection};
|
||||||
use key_server_cluster::cluster_connections_net::{NetConnectionsContainer};
|
use key_server_cluster::cluster_connections_net::{NetConnectionsContainer};
|
||||||
use types::{Error, NodeId};
|
use types::{Error, NodeId};
|
||||||
use NodeKeyPair;
|
use blockchain::SigningKeyPair;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
/// Describes which maintain() call is required.
|
/// Describes which maintain() call is required.
|
||||||
@ -93,7 +93,7 @@ pub enum ConnectionsAction {
|
|||||||
/// Trigger connections.
|
/// Trigger connections.
|
||||||
pub struct TriggerConnections {
|
pub struct TriggerConnections {
|
||||||
/// This node key pair.
|
/// This node key pair.
|
||||||
pub self_key_pair: Arc<dyn NodeKeyPair>,
|
pub self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleConnectionTrigger {
|
impl SimpleConnectionTrigger {
|
||||||
@ -103,7 +103,7 @@ impl SimpleConnectionTrigger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create new simple connection trigger.
|
/// Create new simple connection trigger.
|
||||||
pub fn new(key_server_set: Arc<dyn KeyServerSet>, self_key_pair: Arc<dyn NodeKeyPair>, admin_public: Option<Public>) -> Self {
|
pub fn new(key_server_set: Arc<dyn KeyServerSet>, self_key_pair: Arc<dyn SigningKeyPair>, admin_public: Option<Public>) -> Self {
|
||||||
SimpleConnectionTrigger {
|
SimpleConnectionTrigger {
|
||||||
key_server_set: key_server_set,
|
key_server_set: key_server_set,
|
||||||
connections: TriggerConnections {
|
connections: TriggerConnections {
|
||||||
|
@ -28,12 +28,12 @@ use key_server_cluster::jobs::servers_set_change_access_job::ordered_nodes_hash;
|
|||||||
use key_server_cluster::connection_trigger::{Maintain, ConnectionsAction, ConnectionTrigger,
|
use key_server_cluster::connection_trigger::{Maintain, ConnectionsAction, ConnectionTrigger,
|
||||||
ServersSetChangeSessionCreatorConnector, TriggerConnections};
|
ServersSetChangeSessionCreatorConnector, TriggerConnections};
|
||||||
use types::{Error, NodeId};
|
use types::{Error, NodeId};
|
||||||
use {NodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
|
||||||
/// Key servers set change trigger with automated migration procedure.
|
/// Key servers set change trigger with automated migration procedure.
|
||||||
pub struct ConnectionTriggerWithMigration {
|
pub struct ConnectionTriggerWithMigration {
|
||||||
/// This node key pair.
|
/// This node key pair.
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
/// Key server set.
|
/// Key server set.
|
||||||
key_server_set: Arc<dyn KeyServerSet>,
|
key_server_set: Arc<dyn KeyServerSet>,
|
||||||
/// Last server set state.
|
/// Last server set state.
|
||||||
@ -105,7 +105,7 @@ struct TriggerSession {
|
|||||||
/// Servers set change session creator connector.
|
/// Servers set change session creator connector.
|
||||||
connector: Arc<ServersSetChangeSessionCreatorConnectorWithMigration>,
|
connector: Arc<ServersSetChangeSessionCreatorConnectorWithMigration>,
|
||||||
/// This node key pair.
|
/// This node key pair.
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
/// Key server set.
|
/// Key server set.
|
||||||
key_server_set: Arc<dyn KeyServerSet>,
|
key_server_set: Arc<dyn KeyServerSet>,
|
||||||
}
|
}
|
||||||
@ -117,7 +117,7 @@ impl ConnectionTriggerWithMigration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create new trigge with migration.
|
/// Create new trigge with migration.
|
||||||
pub fn new(key_server_set: Arc<dyn KeyServerSet>, self_key_pair: Arc<dyn NodeKeyPair>) -> Self {
|
pub fn new(key_server_set: Arc<dyn KeyServerSet>, self_key_pair: Arc<dyn SigningKeyPair>) -> Self {
|
||||||
let snapshot = key_server_set.snapshot();
|
let snapshot = key_server_set.snapshot();
|
||||||
let migration = snapshot.migration.clone();
|
let migration = snapshot.migration.clone();
|
||||||
|
|
||||||
|
@ -40,20 +40,21 @@ use tokio_io::{AsyncRead, AsyncWrite};
|
|||||||
use crypto::publickey::ecdh::agree;
|
use crypto::publickey::ecdh::agree;
|
||||||
use crypto::publickey::{Random, Generator, KeyPair, Public, Signature, verify_public, sign, recover};
|
use crypto::publickey::{Random, Generator, KeyPair, Public, Signature, verify_public, sign, recover};
|
||||||
use ethereum_types::H256;
|
use ethereum_types::H256;
|
||||||
use key_server_cluster::{NodeId, Error, NodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
use key_server_cluster::{NodeId, Error};
|
||||||
use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature};
|
use key_server_cluster::message::{Message, ClusterMessage, NodePublicKey, NodePrivateKeySignature};
|
||||||
use key_server_cluster::io::{write_message, write_encrypted_message, WriteMessage, ReadMessage,
|
use key_server_cluster::io::{write_message, write_encrypted_message, WriteMessage, ReadMessage,
|
||||||
read_message, read_encrypted_message, fix_shared_key};
|
read_message, read_encrypted_message, fix_shared_key};
|
||||||
|
|
||||||
/// Start handshake procedure with another node from the cluster.
|
/// Start handshake procedure with another node from the cluster.
|
||||||
pub fn handshake<A>(a: A, self_key_pair: Arc<dyn NodeKeyPair>, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead {
|
pub fn handshake<A>(a: A, self_key_pair: Arc<dyn SigningKeyPair>, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead {
|
||||||
let init_data = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into)
|
let init_data = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into)
|
||||||
.and_then(|cp| Random.generate().map(|kp| (cp, kp)).map_err(Into::into));
|
.and_then(|cp| Random.generate().map(|kp| (cp, kp)).map_err(Into::into));
|
||||||
handshake_with_init_data(a, init_data, self_key_pair, trusted_nodes)
|
handshake_with_init_data(a, init_data, self_key_pair, trusted_nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start handshake procedure with another node from the cluster and given plain confirmation + session key pair.
|
/// Start handshake procedure with another node from the cluster and given plain confirmation + session key pair.
|
||||||
pub fn handshake_with_init_data<A>(a: A, init_data: Result<(H256, KeyPair), Error>, self_key_pair: Arc<dyn NodeKeyPair>, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead {
|
pub fn handshake_with_init_data<A>(a: A, init_data: Result<(H256, KeyPair), Error>, self_key_pair: Arc<dyn SigningKeyPair>, trusted_nodes: BTreeSet<NodeId>) -> Handshake<A> where A: AsyncWrite + AsyncRead {
|
||||||
let handshake_input_data = init_data
|
let handshake_input_data = init_data
|
||||||
.and_then(|(cp, kp)| sign(kp.secret(), &cp).map(|sp| (cp, kp, sp)).map_err(Into::into))
|
.and_then(|(cp, kp)| sign(kp.secret(), &cp).map(|sp| (cp, kp, sp)).map_err(Into::into))
|
||||||
.and_then(|(cp, kp, sp)| Handshake::<A>::make_public_key_message(self_key_pair.public().clone(), cp.clone(), sp).map(|msg| (cp, kp, msg)));
|
.and_then(|(cp, kp, sp)| Handshake::<A>::make_public_key_message(self_key_pair.public().clone(), cp.clone(), sp).map(|msg| (cp, kp, msg)));
|
||||||
@ -79,7 +80,7 @@ pub fn handshake_with_init_data<A>(a: A, init_data: Result<(H256, KeyPair), Erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Wait for handshake procedure to be started by another node from the cluster.
|
/// Wait for handshake procedure to be started by another node from the cluster.
|
||||||
pub fn accept_handshake<A>(a: A, self_key_pair: Arc<dyn NodeKeyPair>) -> Handshake<A> where A: AsyncWrite + AsyncRead {
|
pub fn accept_handshake<A>(a: A, self_key_pair: Arc<dyn SigningKeyPair>) -> Handshake<A> where A: AsyncWrite + AsyncRead {
|
||||||
let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into);
|
let self_confirmation_plain = Random.generate().map(|kp| *kp.secret().clone()).map_err(Into::into);
|
||||||
let handshake_input_data = self_confirmation_plain
|
let handshake_input_data = self_confirmation_plain
|
||||||
.and_then(|cp| Random.generate().map(|kp| (cp, kp)).map_err(Into::into));
|
.and_then(|cp| Random.generate().map(|kp| (cp, kp)).map_err(Into::into));
|
||||||
@ -118,7 +119,7 @@ pub struct Handshake<A> {
|
|||||||
is_active: bool,
|
is_active: bool,
|
||||||
error: Option<(A, Result<HandshakeResult, Error>)>,
|
error: Option<(A, Result<HandshakeResult, Error>)>,
|
||||||
state: HandshakeState<A>,
|
state: HandshakeState<A>,
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
self_session_key_pair: Option<KeyPair>,
|
self_session_key_pair: Option<KeyPair>,
|
||||||
self_confirmation_plain: H256,
|
self_confirmation_plain: H256,
|
||||||
trusted_nodes: Option<BTreeSet<NodeId>>,
|
trusted_nodes: Option<BTreeSet<NodeId>>,
|
||||||
@ -156,7 +157,7 @@ impl<A> Handshake<A> where A: AsyncRead + AsyncWrite {
|
|||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_private_key_signature_message(self_key_pair: &dyn NodeKeyPair, confirmation_plain: &H256) -> Result<Message, Error> {
|
fn make_private_key_signature_message(self_key_pair: &dyn SigningKeyPair, confirmation_plain: &H256) -> Result<Message, Error> {
|
||||||
Ok(Message::Cluster(ClusterMessage::NodePrivateKeySignature(NodePrivateKeySignature {
|
Ok(Message::Cluster(ClusterMessage::NodePrivateKeySignature(NodePrivateKeySignature {
|
||||||
confirmation_signed: self_key_pair.sign(confirmation_plain)?.into(),
|
confirmation_signed: self_key_pair.sign(confirmation_plain)?.into(),
|
||||||
})))
|
})))
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
use super::types::ServerKeyId;
|
use super::types::ServerKeyId;
|
||||||
|
|
||||||
pub use super::traits::NodeKeyPair;
|
pub use super::blockchain::SigningKeyPair;
|
||||||
pub use super::types::{Error, NodeId, Requester, EncryptedDocumentKeyShadow};
|
pub use super::types::{Error, NodeId, Requester, EncryptedDocumentKeyShadow};
|
||||||
pub use super::acl_storage::AclStorage;
|
pub use super::acl_storage::AclStorage;
|
||||||
pub use super::key_storage::{KeyStorage, DocumentKeyShare, DocumentKeyShareVersion};
|
pub use super::key_storage::{KeyStorage, DocumentKeyShare, DocumentKeyShareVersion};
|
||||||
|
@ -20,12 +20,13 @@ use std::net::SocketAddr;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use futures::{Future, Poll};
|
use futures::{Future, Poll};
|
||||||
use tokio::net::TcpStream;
|
use tokio::net::TcpStream;
|
||||||
use key_server_cluster::{Error, NodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
use key_server_cluster::Error;
|
||||||
use key_server_cluster::io::{accept_handshake, Handshake, Deadline, deadline};
|
use key_server_cluster::io::{accept_handshake, Handshake, Deadline, deadline};
|
||||||
use key_server_cluster::net::Connection;
|
use key_server_cluster::net::Connection;
|
||||||
|
|
||||||
/// Create future for accepting incoming connection.
|
/// Create future for accepting incoming connection.
|
||||||
pub fn accept_connection(stream: TcpStream, self_key_pair: Arc<dyn NodeKeyPair>) -> Deadline<AcceptConnection> {
|
pub fn accept_connection(stream: TcpStream, self_key_pair: Arc<dyn SigningKeyPair>) -> Deadline<AcceptConnection> {
|
||||||
// TODO: This could fail so it would be better either to accept the
|
// TODO: This could fail so it would be better either to accept the
|
||||||
// address as a separate argument or return a result.
|
// address as a separate argument or return a result.
|
||||||
let address = stream.peer_addr().expect("Unable to determine tcp peer address");
|
let address = stream.peer_addr().expect("Unable to determine tcp peer address");
|
||||||
|
@ -21,12 +21,13 @@ use std::time::Duration;
|
|||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use futures::{Future, Poll, Async};
|
use futures::{Future, Poll, Async};
|
||||||
use tokio::net::{TcpStream, tcp::ConnectFuture};
|
use tokio::net::{TcpStream, tcp::ConnectFuture};
|
||||||
use key_server_cluster::{Error, NodeId, NodeKeyPair};
|
use blockchain::SigningKeyPair;
|
||||||
|
use key_server_cluster::{Error, NodeId};
|
||||||
use key_server_cluster::io::{handshake, Handshake, Deadline, deadline};
|
use key_server_cluster::io::{handshake, Handshake, Deadline, deadline};
|
||||||
use key_server_cluster::net::Connection;
|
use key_server_cluster::net::Connection;
|
||||||
|
|
||||||
/// Create future for connecting to other node.
|
/// Create future for connecting to other node.
|
||||||
pub fn connect(address: &SocketAddr, self_key_pair: Arc<dyn NodeKeyPair>, trusted_nodes: BTreeSet<NodeId>) -> Deadline<Connect> {
|
pub fn connect(address: &SocketAddr, self_key_pair: Arc<dyn SigningKeyPair>, trusted_nodes: BTreeSet<NodeId>) -> Deadline<Connect> {
|
||||||
let connect = Connect {
|
let connect = Connect {
|
||||||
state: ConnectState::TcpConnect(TcpStream::connect(address)),
|
state: ConnectState::TcpConnect(TcpStream::connect(address)),
|
||||||
address: address.clone(),
|
address: address.clone(),
|
||||||
@ -47,7 +48,7 @@ enum ConnectState {
|
|||||||
pub struct Connect {
|
pub struct Connect {
|
||||||
state: ConnectState,
|
state: ConnectState,
|
||||||
address: SocketAddr,
|
address: SocketAddr,
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
trusted_nodes: BTreeSet<NodeId>,
|
trusted_nodes: BTreeSet<NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,20 +18,12 @@ use std::sync::Arc;
|
|||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::collections::{BTreeMap, HashSet};
|
use std::collections::{BTreeMap, HashSet};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use call_contract::CallContract;
|
|
||||||
use ethabi::FunctionOutputDecoder;
|
use ethabi::FunctionOutputDecoder;
|
||||||
use ethcore::client::Client;
|
|
||||||
use client_traits::{BlockChainClient, ChainNotify};
|
|
||||||
use common_types::{
|
|
||||||
chain_notify::NewBlocks,
|
|
||||||
ids::BlockId,
|
|
||||||
};
|
|
||||||
use ethereum_types::{H256, Address};
|
use ethereum_types::{H256, Address};
|
||||||
use crypto::publickey::public_to_address;
|
use crypto::publickey::public_to_address;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use types::{Error, Public, NodeAddress, NodeId};
|
use types::{Error, Public, NodeAddress, NodeId};
|
||||||
use trusted_client::TrustedClient;
|
use blockchain::{SecretStoreChain, NewBlocksNotify, SigningKeyPair, ContractAddress, BlockId};
|
||||||
use {NodeKeyPair, ContractAddress};
|
|
||||||
|
|
||||||
use_contract!(key_server, "res/key_server_set.json");
|
use_contract!(key_server, "res/key_server_set.json");
|
||||||
|
|
||||||
@ -105,7 +97,7 @@ struct PreviousMigrationTransaction {
|
|||||||
/// Cached on-chain Key Server set contract.
|
/// Cached on-chain Key Server set contract.
|
||||||
struct CachedContract {
|
struct CachedContract {
|
||||||
/// Blockchain client.
|
/// Blockchain client.
|
||||||
client: TrustedClient,
|
client: Arc<dyn SecretStoreChain>,
|
||||||
/// Contract address source.
|
/// Contract address source.
|
||||||
contract_address_source: Option<ContractAddress>,
|
contract_address_source: Option<ContractAddress>,
|
||||||
/// Current contract address.
|
/// Current contract address.
|
||||||
@ -121,18 +113,15 @@ struct CachedContract {
|
|||||||
/// Previous confirm migration transaction.
|
/// Previous confirm migration transaction.
|
||||||
confirm_migration_tx: Option<PreviousMigrationTransaction>,
|
confirm_migration_tx: Option<PreviousMigrationTransaction>,
|
||||||
/// This node key pair.
|
/// This node key pair.
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OnChainKeyServerSet {
|
impl OnChainKeyServerSet {
|
||||||
pub fn new(trusted_client: TrustedClient, contract_address_source: Option<ContractAddress>, self_key_pair: Arc<dyn NodeKeyPair>, auto_migrate_enabled: bool, key_servers: BTreeMap<Public, NodeAddress>) -> Result<Arc<Self>, Error> {
|
pub fn new(trusted_client: Arc<dyn SecretStoreChain>, contract_address_source: Option<ContractAddress>, self_key_pair: Arc<dyn SigningKeyPair>, auto_migrate_enabled: bool, key_servers: BTreeMap<Public, NodeAddress>) -> Result<Arc<Self>, Error> {
|
||||||
let client = trusted_client.get_untrusted();
|
|
||||||
let key_server_set = Arc::new(OnChainKeyServerSet {
|
let key_server_set = Arc::new(OnChainKeyServerSet {
|
||||||
contract: Mutex::new(CachedContract::new(trusted_client, contract_address_source, self_key_pair, auto_migrate_enabled, key_servers)?),
|
contract: Mutex::new(CachedContract::new(trusted_client.clone(), contract_address_source, self_key_pair, auto_migrate_enabled, key_servers)?),
|
||||||
});
|
});
|
||||||
client
|
trusted_client.add_listener(key_server_set.clone());
|
||||||
.ok_or_else(|| Error::Internal("Constructing OnChainKeyServerSet without active Client".into()))?
|
|
||||||
.add_notify(key_server_set.clone());
|
|
||||||
Ok(key_server_set)
|
Ok(key_server_set)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,14 +144,9 @@ impl KeyServerSet for OnChainKeyServerSet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChainNotify for OnChainKeyServerSet {
|
impl NewBlocksNotify for OnChainKeyServerSet {
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, _new_enacted_len: usize) {
|
||||||
if new_blocks.has_more_blocks_to_import { return }
|
self.contract.lock().update()
|
||||||
let (enacted, retracted) = new_blocks.route.into_enacted_retracted();
|
|
||||||
|
|
||||||
if !enacted.is_empty() || !retracted.is_empty() {
|
|
||||||
self.contract.lock().update(enacted, retracted)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +216,7 @@ impl <F: Fn(Vec<u8>) -> Result<Vec<u8>, String>> KeyServerSubset<F> for NewKeySe
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CachedContract {
|
impl CachedContract {
|
||||||
pub fn new(client: TrustedClient, contract_address_source: Option<ContractAddress>, self_key_pair: Arc<dyn NodeKeyPair>, auto_migrate_enabled: bool, key_servers: BTreeMap<Public, NodeAddress>) -> Result<Self, Error> {
|
pub fn new(client: Arc<dyn SecretStoreChain>, contract_address_source: Option<ContractAddress>, self_key_pair: Arc<dyn SigningKeyPair>, auto_migrate_enabled: bool, key_servers: BTreeMap<Public, NodeAddress>) -> Result<Self, Error> {
|
||||||
let server_set = match contract_address_source.is_none() {
|
let server_set = match contract_address_source.is_none() {
|
||||||
true => key_servers.into_iter()
|
true => key_servers.into_iter()
|
||||||
.map(|(p, addr)| {
|
.map(|(p, addr)| {
|
||||||
@ -279,21 +263,19 @@ impl CachedContract {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, enacted: Vec<H256>, retracted: Vec<H256>) {
|
pub fn update(&mut self) {
|
||||||
// no need to update when servers set is hardcoded
|
// no need to update when servers set is hardcoded
|
||||||
if self.contract_address_source.is_none() {
|
if self.contract_address_source.is_none() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(client) = self.client.get() {
|
if self.client.is_trusted() {
|
||||||
// read new snapshot from reqistry (if something has chnaged)
|
// read new snapshot from reqistry
|
||||||
if !enacted.is_empty() || !retracted.is_empty() {
|
|
||||||
self.update_contract_address();
|
self.update_contract_address();
|
||||||
self.read_from_registry(&*client);
|
self.read_from_registry();
|
||||||
}
|
|
||||||
|
|
||||||
// update number of confirmations (if there's future new set)
|
// update number of confirmations (if there's future new set)
|
||||||
self.update_number_of_confirmations_if_required(&*client);
|
self.update_number_of_confirmations_if_required();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,9 +289,9 @@ impl CachedContract {
|
|||||||
|
|
||||||
fn start_migration(&mut self, migration_id: H256) {
|
fn start_migration(&mut self, migration_id: H256) {
|
||||||
// trust is not needed here, because it is the reaction to the read of the trusted client
|
// trust is not needed here, because it is the reaction to the read of the trusted client
|
||||||
if let (Some(client), Some(contract_address)) = (self.client.get_untrusted(), self.contract_address.as_ref()) {
|
if let Some(contract_address) = self.contract_address.as_ref() {
|
||||||
// check if we need to send start migration transaction
|
// check if we need to send start migration transaction
|
||||||
if !update_last_transaction_block(&*client, &migration_id, &mut self.start_migration_tx) {
|
if !update_last_transaction_block(&*self.client, &migration_id, &mut self.start_migration_tx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -328,9 +310,9 @@ impl CachedContract {
|
|||||||
|
|
||||||
fn confirm_migration(&mut self, migration_id: H256) {
|
fn confirm_migration(&mut self, migration_id: H256) {
|
||||||
// trust is not needed here, because we have already completed the action
|
// trust is not needed here, because we have already completed the action
|
||||||
if let (Some(client), Some(contract_address)) = (self.client.get(), self.contract_address) {
|
if let (true, Some(contract_address)) = (self.client.is_trusted(), self.contract_address) {
|
||||||
// check if we need to send start migration transaction
|
// check if we need to send start migration transaction
|
||||||
if !update_last_transaction_block(&*client, &migration_id, &mut self.confirm_migration_tx) {
|
if !update_last_transaction_block(&*self.client, &migration_id, &mut self.confirm_migration_tx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +329,7 @@ impl CachedContract {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_from_registry(&mut self, client: &Client) {
|
fn read_from_registry(&mut self) {
|
||||||
let contract_address = match self.contract_address {
|
let contract_address = match self.contract_address {
|
||||||
Some(contract_address) => contract_address,
|
Some(contract_address) => contract_address,
|
||||||
None => {
|
None => {
|
||||||
@ -361,7 +343,7 @@ impl CachedContract {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let do_call = |data| client.call_contract(BlockId::Latest, contract_address, data);
|
let do_call = |data| self.client.call_contract(BlockId::Latest, contract_address, data);
|
||||||
|
|
||||||
let current_set = Self::read_key_server_set(CurrentKeyServerSubset, &do_call);
|
let current_set = Self::read_key_server_set(CurrentKeyServerSubset, &do_call);
|
||||||
|
|
||||||
@ -434,7 +416,7 @@ impl CachedContract {
|
|||||||
|
|
||||||
// we might want to adjust new_set if auto migration is enabled
|
// we might want to adjust new_set if auto migration is enabled
|
||||||
if self.auto_migrate_enabled {
|
if self.auto_migrate_enabled {
|
||||||
let block = client.block_hash(BlockId::Latest).unwrap_or_default();
|
let block = self.client.block_hash(BlockId::Latest).unwrap_or_default();
|
||||||
update_future_set(&mut self.future_new_set, &mut new_snapshot, block);
|
update_future_set(&mut self.future_new_set, &mut new_snapshot, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -474,14 +456,14 @@ impl CachedContract {
|
|||||||
key_servers
|
key_servers
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_number_of_confirmations_if_required(&mut self, client: &dyn BlockChainClient) {
|
fn update_number_of_confirmations_if_required(&mut self) {
|
||||||
if !self.auto_migrate_enabled {
|
if !self.auto_migrate_enabled {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
let client = &*self.client;
|
||||||
update_number_of_confirmations(
|
update_number_of_confirmations(
|
||||||
&|| latest_block_hash(&*client),
|
&|| latest_block_hash(client),
|
||||||
&|block| block_confirmations(&*client, block),
|
&|block| block_confirmations(client, block),
|
||||||
&mut self.future_new_set, &mut self.snapshot);
|
&mut self.future_new_set, &mut self.snapshot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -549,7 +531,7 @@ fn update_number_of_confirmations<F1: Fn() -> H256, F2: Fn(H256) -> Option<u64>>
|
|||||||
snapshot.new_set = future_new_set.new_set;
|
snapshot.new_set = future_new_set.new_set;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_last_transaction_block(client: &Client, migration_id: &H256, previous_transaction: &mut Option<PreviousMigrationTransaction>) -> bool {
|
fn update_last_transaction_block(client: &dyn SecretStoreChain, migration_id: &H256, previous_transaction: &mut Option<PreviousMigrationTransaction>) -> bool {
|
||||||
let last_block = client.block_number(BlockId::Latest).unwrap_or_default();
|
let last_block = client.block_number(BlockId::Latest).unwrap_or_default();
|
||||||
match previous_transaction.as_ref() {
|
match previous_transaction.as_ref() {
|
||||||
// no previous transaction => send immediately
|
// no previous transaction => send immediately
|
||||||
@ -577,11 +559,11 @@ fn update_last_transaction_block(client: &Client, migration_id: &H256, previous_
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn latest_block_hash(client: &dyn BlockChainClient) -> H256 {
|
fn latest_block_hash(client: &dyn SecretStoreChain) -> H256 {
|
||||||
client.block_hash(BlockId::Latest).unwrap_or_default()
|
client.block_hash(BlockId::Latest).unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_confirmations(client: &dyn BlockChainClient, block: H256) -> Option<u64> {
|
fn block_confirmations(client: &dyn SecretStoreChain, block: H256) -> Option<u64> {
|
||||||
client.block_number(BlockId::Hash(block))
|
client.block_number(BlockId::Hash(block))
|
||||||
.and_then(|block| client.block_number(BlockId::Latest).map(|last_block| (block, last_block)))
|
.and_then(|block| client.block_number(BlockId::Latest).map(|last_block| (block, last_block)))
|
||||||
.map(|(block, last_block)| last_block - block)
|
.map(|(block, last_block)| last_block - block)
|
||||||
|
@ -15,12 +15,7 @@
|
|||||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
extern crate client_traits;
|
|
||||||
extern crate common_types;
|
|
||||||
extern crate ethabi;
|
extern crate ethabi;
|
||||||
extern crate ethcore;
|
|
||||||
extern crate ethcore_call_contract as call_contract;
|
|
||||||
extern crate ethcore_sync as sync;
|
|
||||||
extern crate ethereum_types;
|
extern crate ethereum_types;
|
||||||
extern crate hyper;
|
extern crate hyper;
|
||||||
extern crate keccak_hash as hash;
|
extern crate keccak_hash as hash;
|
||||||
@ -31,7 +26,6 @@ extern crate parity_crypto as crypto;
|
|||||||
extern crate parity_runtime;
|
extern crate parity_runtime;
|
||||||
extern crate parking_lot;
|
extern crate parking_lot;
|
||||||
extern crate percent_encoding;
|
extern crate percent_encoding;
|
||||||
extern crate registrar;
|
|
||||||
extern crate rustc_hex;
|
extern crate rustc_hex;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
@ -54,19 +48,13 @@ extern crate lazy_static;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
#[cfg(any(test, feature = "accounts"))]
|
|
||||||
extern crate ethkey;
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate tempdir;
|
extern crate tempdir;
|
||||||
|
|
||||||
#[cfg(feature = "accounts")]
|
|
||||||
extern crate ethcore_accounts as accounts;
|
|
||||||
|
|
||||||
mod key_server_cluster;
|
mod key_server_cluster;
|
||||||
mod types;
|
mod types;
|
||||||
mod helpers;
|
|
||||||
|
|
||||||
mod traits;
|
mod traits;
|
||||||
mod acl_storage;
|
mod acl_storage;
|
||||||
@ -76,23 +64,19 @@ mod serialization;
|
|||||||
mod key_server_set;
|
mod key_server_set;
|
||||||
mod node_key_pair;
|
mod node_key_pair;
|
||||||
mod listener;
|
mod listener;
|
||||||
mod trusted_client;
|
mod blockchain;
|
||||||
mod migration;
|
mod migration;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use kvdb::KeyValueDB;
|
use kvdb::KeyValueDB;
|
||||||
use kvdb_rocksdb::{Database, DatabaseConfig};
|
use kvdb_rocksdb::{Database, DatabaseConfig};
|
||||||
use ethcore::client::Client;
|
|
||||||
use ethcore::miner::Miner;
|
|
||||||
use sync::SyncProvider;
|
|
||||||
use parity_runtime::Executor;
|
use parity_runtime::Executor;
|
||||||
|
|
||||||
pub use types::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public,
|
pub use types::{ServerKeyId, EncryptedDocumentKey, RequestSignature, Public,
|
||||||
Error, NodeAddress, ContractAddress, ServiceConfiguration, ClusterConfiguration};
|
Error, NodeAddress, ServiceConfiguration, ClusterConfiguration};
|
||||||
pub use traits::{NodeKeyPair, KeyServer};
|
pub use traits::KeyServer;
|
||||||
|
pub use blockchain::{SecretStoreChain, SigningKeyPair, ContractAddress, BlockId, BlockNumber, NewBlocksNotify, Filter};
|
||||||
pub use self::node_key_pair::PlainNodeKeyPair;
|
pub use self::node_key_pair::PlainNodeKeyPair;
|
||||||
#[cfg(feature = "accounts")]
|
|
||||||
pub use self::node_key_pair::KeyStoreNodeKeyPair;
|
|
||||||
|
|
||||||
/// Open a secret store DB using the given secret store data path. The DB path is one level beneath the data path.
|
/// Open a secret store DB using the given secret store data path. The DB path is one level beneath the data path.
|
||||||
pub fn open_secretstore_db(data_path: &str) -> Result<Arc<dyn KeyValueDB>, String> {
|
pub fn open_secretstore_db(data_path: &str) -> Result<Arc<dyn KeyValueDB>, String> {
|
||||||
@ -109,10 +93,9 @@ pub fn open_secretstore_db(data_path: &str) -> Result<Arc<dyn KeyValueDB>, Strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Start new key server instance
|
/// Start new key server instance
|
||||||
pub fn start(client: Arc<Client>, sync: Arc<dyn SyncProvider>, miner: Arc<Miner>, self_key_pair: Arc<dyn NodeKeyPair>, mut config: ServiceConfiguration,
|
pub fn start(trusted_client: Arc<dyn SecretStoreChain>, self_key_pair: Arc<dyn SigningKeyPair>, mut config: ServiceConfiguration,
|
||||||
db: Arc<dyn KeyValueDB>, executor: Executor) -> Result<Box<dyn KeyServer>, Error>
|
db: Arc<dyn KeyValueDB>, executor: Executor) -> Result<Box<dyn KeyServer>, Error>
|
||||||
{
|
{
|
||||||
let trusted_client = trusted_client::TrustedClient::new(self_key_pair.clone(), client.clone(), sync, miner);
|
|
||||||
let acl_storage: Arc<dyn acl_storage::AclStorage> = match config.acl_check_contract_address.take() {
|
let acl_storage: Arc<dyn acl_storage::AclStorage> = match config.acl_check_contract_address.take() {
|
||||||
Some(acl_check_contract_address) => acl_storage::OnChainAclStorage::new(trusted_client.clone(), acl_check_contract_address)?,
|
Some(acl_check_contract_address) => acl_storage::OnChainAclStorage::new(trusted_client.clone(), acl_check_contract_address)?,
|
||||||
None => Arc::new(acl_storage::DummyAclStorage::default()),
|
None => Arc::new(acl_storage::DummyAclStorage::default()),
|
||||||
@ -186,7 +169,7 @@ pub fn start(client: Arc<Client>, sync: Arc<dyn SyncProvider>, miner: Arc<Miner>
|
|||||||
key_storage: key_storage,
|
key_storage: key_storage,
|
||||||
}
|
}
|
||||||
)?;
|
)?;
|
||||||
client.add_notify(listener.clone());
|
trusted_client.add_listener(listener.clone());
|
||||||
listener
|
listener
|
||||||
}),
|
}),
|
||||||
None => None,
|
None => None,
|
||||||
|
@ -16,22 +16,16 @@
|
|||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
use common_types::filter::Filter;
|
|
||||||
use ethabi::RawLog;
|
use ethabi::RawLog;
|
||||||
use ethabi::FunctionOutputDecoder;
|
use ethabi::FunctionOutputDecoder;
|
||||||
use call_contract::CallContract;
|
|
||||||
use ethcore::client::Client;
|
|
||||||
use client_traits::BlockChainClient;
|
|
||||||
use common_types::ids::BlockId;
|
|
||||||
use crypto::publickey::{Public, public_to_address};
|
use crypto::publickey::{Public, public_to_address};
|
||||||
use hash::keccak;
|
use hash::keccak;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use ethereum_types::{H256, U256, Address, H512};
|
use ethereum_types::{H256, U256, Address, H512};
|
||||||
use listener::ApiMask;
|
use listener::ApiMask;
|
||||||
use listener::service_contract_listener::ServiceTask;
|
use listener::service_contract_listener::ServiceTask;
|
||||||
use trusted_client::TrustedClient;
|
use blockchain::{SecretStoreChain, Filter, SigningKeyPair, ContractAddress, BlockId};
|
||||||
use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED};
|
use ServerKeyId;
|
||||||
use {ServerKeyId, NodeKeyPair, ContractAddress};
|
|
||||||
|
|
||||||
use_contract!(service, "res/service.json");
|
use_contract!(service, "res/service.json");
|
||||||
|
|
||||||
@ -98,9 +92,9 @@ pub struct OnChainServiceContract {
|
|||||||
/// Requests mask.
|
/// Requests mask.
|
||||||
mask: ApiMask,
|
mask: ApiMask,
|
||||||
/// Blockchain client.
|
/// Blockchain client.
|
||||||
client: TrustedClient,
|
client: Arc<dyn SecretStoreChain>,
|
||||||
/// This node key pair.
|
/// This node key pair.
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
/// Contract registry name (if any).
|
/// Contract registry name (if any).
|
||||||
name: String,
|
name: String,
|
||||||
/// Contract address source.
|
/// Contract address source.
|
||||||
@ -138,7 +132,7 @@ struct DocumentKeyShadowRetrievalService;
|
|||||||
|
|
||||||
impl OnChainServiceContract {
|
impl OnChainServiceContract {
|
||||||
/// Create new on-chain service contract.
|
/// Create new on-chain service contract.
|
||||||
pub fn new(mask: ApiMask, client: TrustedClient, name: String, address_source: ContractAddress, self_key_pair: Arc<dyn NodeKeyPair>) -> Self {
|
pub fn new(mask: ApiMask, client: Arc<dyn SecretStoreChain>, name: String, address_source: ContractAddress, self_key_pair: Arc<dyn SigningKeyPair>) -> Self {
|
||||||
let contract = OnChainServiceContract {
|
let contract = OnChainServiceContract {
|
||||||
mask: mask,
|
mask: mask,
|
||||||
client: client,
|
client: client,
|
||||||
@ -157,24 +151,23 @@ impl OnChainServiceContract {
|
|||||||
|
|
||||||
/// Send transaction to the service contract.
|
/// Send transaction to the service contract.
|
||||||
fn send_contract_transaction<C, P>(&self, tx_name: &str, origin: &Address, server_key_id: &ServerKeyId, is_response_required: C, prepare_tx: P) -> Result<(), String>
|
fn send_contract_transaction<C, P>(&self, tx_name: &str, origin: &Address, server_key_id: &ServerKeyId, is_response_required: C, prepare_tx: P) -> Result<(), String>
|
||||||
where C: FnOnce(&Client, &Address, &ServerKeyId, &Address) -> bool,
|
where C: FnOnce(&dyn SecretStoreChain, &Address, &ServerKeyId, &Address) -> bool,
|
||||||
P: FnOnce(&Client, &Address) -> Result<Bytes, String> {
|
P: FnOnce(&dyn SecretStoreChain, &Address) -> Result<Bytes, String> {
|
||||||
// only publish if contract address is set && client is online
|
// only publish if contract address is set && client is online
|
||||||
let client = match self.client.get() {
|
if !self.client.is_trusted() {
|
||||||
Some(client) => client,
|
return Err("trusted 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
|
// only publish key if contract waits for publication
|
||||||
// failing is ok here - it could be that enough confirmations have been recevied
|
// failing is ok here - it could be that enough confirmations have been recevied
|
||||||
// or key has been requested using HTTP API
|
// or key has been requested using HTTP API
|
||||||
let self_address = public_to_address(self.self_key_pair.public());
|
let self_address = public_to_address(self.self_key_pair.public());
|
||||||
if !is_response_required(&*client, origin, server_key_id, &self_address) {
|
if !is_response_required(&*self.client, origin, server_key_id, &self_address) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare transaction data
|
// prepare transaction data
|
||||||
let transaction_data = prepare_tx(&*client, origin)?;
|
let transaction_data = prepare_tx(&*self.client, origin)?;
|
||||||
|
|
||||||
// send transaction
|
// send transaction
|
||||||
self.client.transact_contract(
|
self.client.transact_contract(
|
||||||
@ -190,9 +183,9 @@ impl OnChainServiceContract {
|
|||||||
|
|
||||||
/// Create task-specific pending requests iterator.
|
/// Create task-specific pending requests iterator.
|
||||||
fn create_pending_requests_iterator<
|
fn create_pending_requests_iterator<
|
||||||
C: 'static + Fn(&Client, &Address, &BlockId) -> Result<U256, String>,
|
C: 'static + Fn(&dyn SecretStoreChain, &Address, &BlockId) -> Result<U256, String>,
|
||||||
R: 'static + Fn(&dyn NodeKeyPair, &Client, &Address, &BlockId, U256) -> Result<(bool, ServiceTask), String>
|
R: 'static + Fn(&dyn SigningKeyPair, &dyn SecretStoreChain, &Address, &BlockId, U256) -> Result<(bool, ServiceTask), String>
|
||||||
>(&self, client: Arc<Client>, contract_address: &Address, block: &BlockId, get_count: C, read_item: R) -> Box<dyn Iterator<Item=(bool, ServiceTask)>> {
|
>(&self, client: Arc<dyn SecretStoreChain>, contract_address: &Address, block: &BlockId, get_count: C, read_item: R) -> Box<dyn Iterator<Item=(bool, ServiceTask)>> {
|
||||||
get_count(&*client, contract_address, block)
|
get_count(&*client, contract_address, block)
|
||||||
.map(|count| {
|
.map(|count| {
|
||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
@ -237,67 +230,46 @@ impl OnChainServiceContract {
|
|||||||
|
|
||||||
impl ServiceContract for OnChainServiceContract {
|
impl ServiceContract for OnChainServiceContract {
|
||||||
fn update(&self) -> bool {
|
fn update(&self) -> bool {
|
||||||
self.update_contract_address() && self.client.get().is_some()
|
self.update_contract_address() && self.client.is_trusted()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_logs(&self) -> Box<dyn Iterator<Item=ServiceTask>> {
|
fn read_logs(&self) -> Box<dyn Iterator<Item=ServiceTask>> {
|
||||||
let client = match self.client.get() {
|
if !self.client.is_trusted() {
|
||||||
Some(client) => client,
|
|
||||||
None => {
|
|
||||||
warn!(target: "secretstore", "{}: client is offline during read_logs call",
|
warn!(target: "secretstore", "{}: client is offline during read_logs call",
|
||||||
self.self_key_pair.public());
|
self.self_key_pair.public());
|
||||||
return Box::new(::std::iter::empty());
|
return Box::new(::std::iter::empty());
|
||||||
},
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// prepare range of blocks to read logs from
|
let address = match self.data.read().contract_address {
|
||||||
let (address, first_block, last_block) = {
|
|
||||||
let mut data = self.data.write();
|
|
||||||
let address = match data.contract_address {
|
|
||||||
Some(address) => address,
|
Some(address) => address,
|
||||||
None => return Box::new(::std::iter::empty()), // no contract installed
|
None => return Box::new(::std::iter::empty()), // no contract installed
|
||||||
};
|
};
|
||||||
let confirmed_block = match get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED) {
|
let confirmed_block = match self.client.get_confirmed_block_hash() {
|
||||||
Some(confirmed_block) => confirmed_block,
|
Some(confirmed_block) => confirmed_block,
|
||||||
None => return Box::new(::std::iter::empty()), // no block with enough confirmations
|
None => return Box::new(::std::iter::empty()), // no block with enough confirmations
|
||||||
};
|
};
|
||||||
let first_block = match data.last_log_block.take().and_then(|b| client.tree_route(&b, &confirmed_block)) {
|
|
||||||
// if we have a route from last_log_block to confirmed_block => search for logs on this route
|
|
||||||
//
|
|
||||||
// potentially this could lead us to reading same logs twice when reorganizing to the fork, which
|
|
||||||
// already has been canonical previosuly
|
|
||||||
// the worst thing that can happen in this case is spending some time reading unneeded data from SS db
|
|
||||||
Some(ref route) if route.index < route.blocks.len() => route.blocks[route.index],
|
|
||||||
// else we care only about confirmed block
|
|
||||||
_ => confirmed_block.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
data.last_log_block = Some(confirmed_block.clone());
|
let request_logs = self.client.retrieve_last_logs(Filter {
|
||||||
(address, first_block, confirmed_block)
|
from_block: BlockId::Hash(self.data.read().last_log_block.unwrap_or_else(|| confirmed_block)),
|
||||||
};
|
|
||||||
|
|
||||||
// read server key generation requests
|
|
||||||
let request_logs = client.logs(Filter {
|
|
||||||
from_block: BlockId::Hash(first_block),
|
|
||||||
to_block: BlockId::Hash(last_block),
|
|
||||||
address: Some(vec![address]),
|
address: Some(vec![address]),
|
||||||
topics: vec![Some(mask_topics(&self.mask))],
|
topics: vec![Some(mask_topics(&self.mask))],
|
||||||
limit: None,
|
|
||||||
}).unwrap_or_default();
|
}).unwrap_or_default();
|
||||||
|
|
||||||
|
let mut data = self.data.write();
|
||||||
|
data.last_log_block = Some(confirmed_block.clone());
|
||||||
|
|
||||||
Box::new(request_logs.into_iter()
|
Box::new(request_logs.into_iter()
|
||||||
.filter_map(|log| {
|
.filter_map(|log| {
|
||||||
let raw_log: RawLog = (log.entry.topics.into_iter().map(|t| t.0.into()).collect(), log.entry.data).into();
|
if log.topics[0] == *SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME_HASH {
|
||||||
if raw_log.topics[0] == *SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME_HASH {
|
ServerKeyGenerationService::parse_log(&address, log)
|
||||||
ServerKeyGenerationService::parse_log(&address, raw_log)
|
} else if log.topics[0] == *SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME_HASH {
|
||||||
} else if raw_log.topics[0] == *SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME_HASH {
|
ServerKeyRetrievalService::parse_log(&address, log)
|
||||||
ServerKeyRetrievalService::parse_log(&address, raw_log)
|
} else if log.topics[0] == *DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME_HASH {
|
||||||
} else if raw_log.topics[0] == *DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME_HASH {
|
DocumentKeyStoreService::parse_log(&address, log)
|
||||||
DocumentKeyStoreService::parse_log(&address, raw_log)
|
} else if log.topics[0] == *DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH {
|
||||||
} else if raw_log.topics[0] == *DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH {
|
DocumentKeyShadowRetrievalService::parse_common_request_log(&address, log)
|
||||||
DocumentKeyShadowRetrievalService::parse_common_request_log(&address, raw_log)
|
} else if log.topics[0] == *DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH {
|
||||||
} else if raw_log.topics[0] == *DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH {
|
DocumentKeyShadowRetrievalService::parse_personal_request_log(&address, log)
|
||||||
DocumentKeyShadowRetrievalService::parse_personal_request_log(&address, raw_log)
|
|
||||||
} else {
|
} else {
|
||||||
Err("unknown type of log entry".into())
|
Err("unknown type of log entry".into())
|
||||||
}
|
}
|
||||||
@ -311,39 +283,37 @@ impl ServiceContract for OnChainServiceContract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn read_pending_requests(&self) -> Box<dyn Iterator<Item=(bool, ServiceTask)>> {
|
fn read_pending_requests(&self) -> Box<dyn Iterator<Item=(bool, ServiceTask)>> {
|
||||||
let client = match self.client.get() {
|
if !self.client.is_trusted() {
|
||||||
Some(client) => client,
|
return Box::new(::std::iter::empty())
|
||||||
None => return Box::new(::std::iter::empty()),
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// we only need requests that are here for more than REQUEST_CONFIRMATIONS_REQUIRED blocks
|
// we only need requests that are here from the last confirm block
|
||||||
// => we're reading from Latest - (REQUEST_CONFIRMATIONS_REQUIRED + 1) block
|
|
||||||
let data = self.data.read();
|
let data = self.data.read();
|
||||||
match data.contract_address {
|
match data.contract_address {
|
||||||
None => Box::new(::std::iter::empty()),
|
None => Box::new(::std::iter::empty()),
|
||||||
Some(contract_address) => get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED + 1)
|
Some(contract_address) => self.client.get_confirmed_block_hash()
|
||||||
.map(|b| {
|
.map(|b| {
|
||||||
let block = BlockId::Hash(b);
|
let block = BlockId::Hash(b);
|
||||||
let iter = match self.mask.server_key_generation_requests {
|
let iter = match self.mask.server_key_generation_requests {
|
||||||
true => Box::new(self.create_pending_requests_iterator(client.clone(), &contract_address, &block,
|
true => Box::new(self.create_pending_requests_iterator(self.client.clone(), &contract_address, &block,
|
||||||
&ServerKeyGenerationService::read_pending_requests_count,
|
&ServerKeyGenerationService::read_pending_requests_count,
|
||||||
&ServerKeyGenerationService::read_pending_request)) as Box<dyn Iterator<Item=(bool, ServiceTask)>>,
|
&ServerKeyGenerationService::read_pending_request)) as Box<dyn Iterator<Item=(bool, ServiceTask)>>,
|
||||||
false => Box::new(::std::iter::empty()),
|
false => Box::new(::std::iter::empty()),
|
||||||
};
|
};
|
||||||
let iter = match self.mask.server_key_retrieval_requests {
|
let iter = match self.mask.server_key_retrieval_requests {
|
||||||
true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &contract_address, &block,
|
true => Box::new(iter.chain(self.create_pending_requests_iterator(self.client.clone(), &contract_address, &block,
|
||||||
&ServerKeyRetrievalService::read_pending_requests_count,
|
&ServerKeyRetrievalService::read_pending_requests_count,
|
||||||
&ServerKeyRetrievalService::read_pending_request))),
|
&ServerKeyRetrievalService::read_pending_request))),
|
||||||
false => iter,
|
false => iter,
|
||||||
};
|
};
|
||||||
let iter = match self.mask.document_key_store_requests {
|
let iter = match self.mask.document_key_store_requests {
|
||||||
true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &contract_address, &block,
|
true => Box::new(iter.chain(self.create_pending_requests_iterator(self.client.clone(), &contract_address, &block,
|
||||||
&DocumentKeyStoreService::read_pending_requests_count,
|
&DocumentKeyStoreService::read_pending_requests_count,
|
||||||
&DocumentKeyStoreService::read_pending_request))),
|
&DocumentKeyStoreService::read_pending_request))),
|
||||||
false => iter,
|
false => iter,
|
||||||
};
|
};
|
||||||
let iter = match self.mask.document_key_shadow_retrieval_requests {
|
let iter = match self.mask.document_key_shadow_retrieval_requests {
|
||||||
true => Box::new(iter.chain(self.create_pending_requests_iterator(client, &contract_address, &block,
|
true => Box::new(iter.chain(self.create_pending_requests_iterator(self.client.clone(), &contract_address, &block,
|
||||||
&DocumentKeyShadowRetrievalService::read_pending_requests_count,
|
&DocumentKeyShadowRetrievalService::read_pending_requests_count,
|
||||||
&DocumentKeyShadowRetrievalService::read_pending_request))),
|
&DocumentKeyShadowRetrievalService::read_pending_request))),
|
||||||
false => iter
|
false => iter
|
||||||
@ -457,7 +427,7 @@ impl ServerKeyGenerationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if response from key server is required.
|
/// Check if response from key server is required.
|
||||||
pub fn is_response_required(client: &Client, contract_address: &Address, server_key_id: &ServerKeyId, key_server: &Address) -> bool {
|
pub fn is_response_required(client: &dyn SecretStoreChain, contract_address: &Address, server_key_id: &ServerKeyId, key_server: &Address) -> bool {
|
||||||
// we're checking confirmation in Latest block, because we're interested in latest contract state here
|
// we're checking confirmation in Latest block, because we're interested in latest contract state here
|
||||||
let (encoded, decoder) = service::functions::is_server_key_generation_response_required::call(*server_key_id, *key_server);
|
let (encoded, decoder) = service::functions::is_server_key_generation_response_required::call(*server_key_id, *key_server);
|
||||||
match client.call_contract(BlockId::Latest, *contract_address, encoded) {
|
match client.call_contract(BlockId::Latest, *contract_address, encoded) {
|
||||||
@ -477,14 +447,14 @@ impl ServerKeyGenerationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read pending requests count.
|
/// Read pending requests count.
|
||||||
fn read_pending_requests_count(client: &Client, contract_address: &Address, block: &BlockId) -> Result<U256, String> {
|
fn read_pending_requests_count(client: &dyn SecretStoreChain, contract_address: &Address, block: &BlockId) -> Result<U256, String> {
|
||||||
let (encoded, decoder) = service::functions::server_key_generation_requests_count::call();
|
let (encoded, decoder) = service::functions::server_key_generation_requests_count::call();
|
||||||
decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read pending request.
|
/// Read pending request.
|
||||||
fn read_pending_request(self_key_pair: &dyn NodeKeyPair, client: &Client, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> {
|
fn read_pending_request(self_key_pair: &dyn SigningKeyPair, client: &dyn SecretStoreChain, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> {
|
||||||
let self_address = public_to_address(self_key_pair.public());
|
let self_address = public_to_address(self_key_pair.public());
|
||||||
|
|
||||||
let (encoded, decoder) = service::functions::get_server_key_generation_request::call(index);
|
let (encoded, decoder) = service::functions::get_server_key_generation_request::call(index);
|
||||||
@ -517,7 +487,7 @@ impl ServerKeyRetrievalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if response from key server is required.
|
/// Check if response from key server is required.
|
||||||
pub fn is_response_required(client: &Client, contract_address: &Address, server_key_id: &ServerKeyId, key_server: &Address) -> bool {
|
pub fn is_response_required(client: &dyn SecretStoreChain, contract_address: &Address, server_key_id: &ServerKeyId, key_server: &Address) -> bool {
|
||||||
// we're checking confirmation in Latest block, because we're interested in latest contract state here
|
// we're checking confirmation in Latest block, because we're interested in latest contract state here
|
||||||
let (encoded, decoder) = service::functions::is_server_key_retrieval_response_required::call(*server_key_id, *key_server);
|
let (encoded, decoder) = service::functions::is_server_key_retrieval_response_required::call(*server_key_id, *key_server);
|
||||||
match client.call_contract(BlockId::Latest, *contract_address, encoded) {
|
match client.call_contract(BlockId::Latest, *contract_address, encoded) {
|
||||||
@ -537,14 +507,14 @@ impl ServerKeyRetrievalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read pending requests count.
|
/// Read pending requests count.
|
||||||
fn read_pending_requests_count(client: &Client, contract_address: &Address, block: &BlockId) -> Result<U256, String> {
|
fn read_pending_requests_count(client: &dyn SecretStoreChain, contract_address: &Address, block: &BlockId) -> Result<U256, String> {
|
||||||
let (encoded, decoder) = service::functions::server_key_retrieval_requests_count::call();
|
let (encoded, decoder) = service::functions::server_key_retrieval_requests_count::call();
|
||||||
decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read pending request.
|
/// Read pending request.
|
||||||
fn read_pending_request(self_key_pair: &dyn NodeKeyPair, client: &Client, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> {
|
fn read_pending_request(self_key_pair: &dyn SigningKeyPair, client: &dyn SecretStoreChain, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> {
|
||||||
let self_address = public_to_address(self_key_pair.public());
|
let self_address = public_to_address(self_key_pair.public());
|
||||||
|
|
||||||
let (encoded, decoder) = service::functions::get_server_key_retrieval_request::call(index);
|
let (encoded, decoder) = service::functions::get_server_key_retrieval_request::call(index);
|
||||||
@ -580,7 +550,7 @@ impl DocumentKeyStoreService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if response from key server is required.
|
/// Check if response from key server is required.
|
||||||
pub fn is_response_required(client: &Client, contract_address: &Address, server_key_id: &ServerKeyId, key_server: &Address) -> bool {
|
pub fn is_response_required(client: &dyn SecretStoreChain, contract_address: &Address, server_key_id: &ServerKeyId, key_server: &Address) -> bool {
|
||||||
// we're checking confirmation in Latest block, because we're interested in latest contract state here
|
// we're checking confirmation in Latest block, because we're interested in latest contract state here
|
||||||
let (encoded, decoder) = service::functions::is_document_key_store_response_required::call(*server_key_id, *key_server);
|
let (encoded, decoder) = service::functions::is_document_key_store_response_required::call(*server_key_id, *key_server);
|
||||||
match client.call_contract(BlockId::Latest, *contract_address, encoded) {
|
match client.call_contract(BlockId::Latest, *contract_address, encoded) {
|
||||||
@ -600,14 +570,14 @@ impl DocumentKeyStoreService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read pending requests count.
|
/// Read pending requests count.
|
||||||
fn read_pending_requests_count(client: &Client, contract_address: &Address, block: &BlockId) -> Result<U256, String> {
|
fn read_pending_requests_count(client: &dyn SecretStoreChain, contract_address: &Address, block: &BlockId) -> Result<U256, String> {
|
||||||
let (encoded, decoder) = service::functions::document_key_store_requests_count::call();
|
let (encoded, decoder) = service::functions::document_key_store_requests_count::call();
|
||||||
decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read pending request.
|
/// Read pending request.
|
||||||
fn read_pending_request(self_key_pair: &dyn NodeKeyPair, client: &Client, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> {
|
fn read_pending_request(self_key_pair: &dyn SigningKeyPair, client: &dyn SecretStoreChain, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> {
|
||||||
let self_address = public_to_address(self_key_pair.public());
|
let self_address = public_to_address(self_key_pair.public());
|
||||||
let (encoded, decoder) = service::functions::get_document_key_store_request::call(index);
|
let (encoded, decoder) = service::functions::get_document_key_store_request::call(index);
|
||||||
let (server_key_id, author, common_point, encrypted_point) = decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
let (server_key_id, author, common_point, encrypted_point) = decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
||||||
@ -647,7 +617,7 @@ impl DocumentKeyShadowRetrievalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if response from key server is required.
|
/// Check if response from key server is required.
|
||||||
pub fn is_response_required(client: &Client, contract_address: &Address, server_key_id: &ServerKeyId, requester: &Address, key_server: &Address) -> bool {
|
pub fn is_response_required(client: &dyn SecretStoreChain, contract_address: &Address, server_key_id: &ServerKeyId, requester: &Address, key_server: &Address) -> bool {
|
||||||
// we're checking confirmation in Latest block, because we're interested in latest contract state here
|
// we're checking confirmation in Latest block, because we're interested in latest contract state here
|
||||||
let (encoded, decoder) = service::functions::is_document_key_shadow_retrieval_response_required::call(*server_key_id, *requester, *key_server);
|
let (encoded, decoder) = service::functions::is_document_key_shadow_retrieval_response_required::call(*server_key_id, *requester, *key_server);
|
||||||
match client.call_contract(BlockId::Latest, *contract_address, encoded) {
|
match client.call_contract(BlockId::Latest, *contract_address, encoded) {
|
||||||
@ -662,7 +632,7 @@ impl DocumentKeyShadowRetrievalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare publish personal key transaction data.
|
/// Prepare publish personal key transaction data.
|
||||||
pub fn prepare_pubish_personal_tx_data(client: &Client, contract_address: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<Bytes, String> {
|
pub fn prepare_pubish_personal_tx_data(client: &dyn SecretStoreChain, contract_address: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<Bytes, String> {
|
||||||
let mut participants_mask = U256::default();
|
let mut participants_mask = U256::default();
|
||||||
for participant in participants {
|
for participant in participants {
|
||||||
let participant_index = Self::map_key_server_address(client, contract_address, participant.clone())
|
let participant_index = Self::map_key_server_address(client, contract_address, participant.clone())
|
||||||
@ -680,14 +650,14 @@ impl DocumentKeyShadowRetrievalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read pending requests count.
|
/// Read pending requests count.
|
||||||
fn read_pending_requests_count(client: &Client, contract_address: &Address, block: &BlockId) -> Result<U256, String> {
|
fn read_pending_requests_count(client: &dyn SecretStoreChain, contract_address: &Address, block: &BlockId) -> Result<U256, String> {
|
||||||
let (encoded, decoder) = service::functions::document_key_shadow_retrieval_requests_count::call();
|
let (encoded, decoder) = service::functions::document_key_shadow_retrieval_requests_count::call();
|
||||||
decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
decoder.decode(&client.call_contract(*block, *contract_address, encoded)?)
|
||||||
.map_err(|e| e.to_string())
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read pending request.
|
/// Read pending request.
|
||||||
fn read_pending_request(self_key_pair: &dyn NodeKeyPair, client: &Client, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> {
|
fn read_pending_request(self_key_pair: &dyn SigningKeyPair, client: &dyn SecretStoreChain, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> {
|
||||||
let self_address = public_to_address(self_key_pair.public());
|
let self_address = public_to_address(self_key_pair.public());
|
||||||
|
|
||||||
let (encoded, decoder) = service::functions::get_document_key_shadow_retrieval_request::call(index);
|
let (encoded, decoder) = service::functions::get_document_key_shadow_retrieval_request::call(index);
|
||||||
@ -717,7 +687,7 @@ impl DocumentKeyShadowRetrievalService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Map from key server address to key server index.
|
/// Map from key server address to key server index.
|
||||||
fn map_key_server_address(client: &Client, contract_address: &Address, key_server: Address) -> Result<u8, String> {
|
fn map_key_server_address(client: &dyn SecretStoreChain, contract_address: &Address, key_server: Address) -> Result<u8, String> {
|
||||||
// we're checking confirmation in Latest block, because tx ,ust be appended to the latest state
|
// we're checking confirmation in Latest block, because tx ,ust be appended to the latest state
|
||||||
let (encoded, decoder) = service::functions::require_key_server::call(key_server);
|
let (encoded, decoder) = service::functions::require_key_server::call(key_server);
|
||||||
let index = decoder.decode(&client.call_contract(BlockId::Latest, *contract_address, encoded)?)
|
let index = decoder.decode(&client.call_contract(BlockId::Latest, *contract_address, encoded)?)
|
||||||
|
@ -18,8 +18,6 @@ use std::collections::HashSet;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use client_traits::ChainNotify;
|
|
||||||
use common_types::chain_notify::NewBlocks;
|
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use crypto::publickey::{Public, public_to_address};
|
use crypto::publickey::{Public, public_to_address};
|
||||||
use ethereum_types::{H256, U256, Address, BigEndianHash as _};
|
use ethereum_types::{H256, U256, Address, BigEndianHash as _};
|
||||||
@ -36,7 +34,8 @@ use parking_lot::Mutex;
|
|||||||
use acl_storage::AclStorage;
|
use acl_storage::AclStorage;
|
||||||
use listener::service_contract::ServiceContract;
|
use listener::service_contract::ServiceContract;
|
||||||
use listener::tasks_queue::TasksQueue;
|
use listener::tasks_queue::TasksQueue;
|
||||||
use {ServerKeyId, NodeKeyPair, Error};
|
use {ServerKeyId, Error};
|
||||||
|
use blockchain::{NewBlocksNotify, SigningKeyPair};
|
||||||
|
|
||||||
/// Retry interval (in blocks). Every RETRY_INTERVAL_BLOCKS blocks each KeyServer reads pending requests from
|
/// Retry interval (in blocks). Every RETRY_INTERVAL_BLOCKS blocks each KeyServer reads pending requests from
|
||||||
/// service contract && tries to re-execute. The reason to have this mechanism is primarily because keys
|
/// service contract && tries to re-execute. The reason to have this mechanism is primarily because keys
|
||||||
@ -64,7 +63,7 @@ pub struct ServiceContractListenerParams {
|
|||||||
/// Service contract.
|
/// Service contract.
|
||||||
pub contract: Arc<dyn ServiceContract>,
|
pub contract: Arc<dyn ServiceContract>,
|
||||||
/// This node key pair.
|
/// This node key pair.
|
||||||
pub self_key_pair: Arc<dyn NodeKeyPair>,
|
pub self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
/// Key servers set.
|
/// Key servers set.
|
||||||
pub key_server_set: Arc<dyn KeyServerSet>,
|
pub key_server_set: Arc<dyn KeyServerSet>,
|
||||||
/// ACL storage reference.
|
/// ACL storage reference.
|
||||||
@ -90,7 +89,7 @@ struct ServiceContractListenerData {
|
|||||||
/// Cluster client reference.
|
/// Cluster client reference.
|
||||||
pub cluster: Arc<dyn ClusterClient>,
|
pub cluster: Arc<dyn ClusterClient>,
|
||||||
/// This node key pair.
|
/// This node key pair.
|
||||||
pub self_key_pair: Arc<dyn NodeKeyPair>,
|
pub self_key_pair: Arc<dyn SigningKeyPair>,
|
||||||
/// Key servers set.
|
/// Key servers set.
|
||||||
pub key_server_set: Arc<dyn KeyServerSet>,
|
pub key_server_set: Arc<dyn KeyServerSet>,
|
||||||
/// Key storage reference.
|
/// Key storage reference.
|
||||||
@ -434,14 +433,8 @@ impl Drop for ServiceContractListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChainNotify for ServiceContractListener {
|
impl NewBlocksNotify for ServiceContractListener {
|
||||||
fn new_blocks(&self, new_blocks: NewBlocks) {
|
fn new_blocks(&self, new_enacted_len: usize) {
|
||||||
if new_blocks.has_more_blocks_to_import { return }
|
|
||||||
let enacted_len = new_blocks.route.enacted().len();
|
|
||||||
if enacted_len == 0 && new_blocks.route.retracted().is_empty() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if !self.data.contract.update() {
|
if !self.data.contract.update() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -450,7 +443,7 @@ impl ChainNotify for ServiceContractListener {
|
|||||||
|
|
||||||
// schedule retry if received enough blocks since last retry
|
// schedule retry if received enough blocks since last retry
|
||||||
// it maybe inaccurate when switching syncing/synced states, but that's ok
|
// it maybe inaccurate when switching syncing/synced states, but that's ok
|
||||||
if self.data.last_retry.fetch_add(enacted_len, Ordering::Relaxed) >= RETRY_INTERVAL_BLOCKS {
|
if self.data.last_retry.fetch_add(new_enacted_len, Ordering::Relaxed) >= RETRY_INTERVAL_BLOCKS {
|
||||||
// shortcut: do not retry if we're isolated from the cluster
|
// shortcut: do not retry if we're isolated from the cluster
|
||||||
if !self.data.key_server_set.is_isolated() {
|
if !self.data.key_server_set.is_isolated() {
|
||||||
self.data.tasks_queue.push(ServiceTask::Retry);
|
self.data.tasks_queue.push(ServiceTask::Retry);
|
||||||
@ -596,7 +589,8 @@ mod tests {
|
|||||||
use key_storage::tests::DummyKeyStorage;
|
use key_storage::tests::DummyKeyStorage;
|
||||||
use key_server_set::KeyServerSet;
|
use key_server_set::KeyServerSet;
|
||||||
use key_server_set::tests::MapKeyServerSet;
|
use key_server_set::tests::MapKeyServerSet;
|
||||||
use {NodeKeyPair, PlainNodeKeyPair, ServerKeyId};
|
use blockchain::SigningKeyPair;
|
||||||
|
use {PlainNodeKeyPair, ServerKeyId};
|
||||||
use super::{ServiceTask, ServiceContractListener, ServiceContractListenerParams, is_processed_by_this_key_server};
|
use super::{ServiceTask, ServiceContractListener, ServiceContractListenerParams, is_processed_by_this_key_server};
|
||||||
use ethereum_types::Address;
|
use ethereum_types::Address;
|
||||||
|
|
||||||
|
@ -14,10 +14,9 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use crypto::publickey::ecdh::agree;
|
|
||||||
use crypto::publickey::{KeyPair, Public, Signature, Error as EthKeyError, sign, public_to_address};
|
use crypto::publickey::{KeyPair, Public, Signature, Error as EthKeyError, sign, public_to_address};
|
||||||
use ethereum_types::{H256, Address};
|
use ethereum_types::{H256, Address};
|
||||||
use traits::NodeKeyPair;
|
use blockchain::SigningKeyPair;
|
||||||
|
|
||||||
pub struct PlainNodeKeyPair {
|
pub struct PlainNodeKeyPair {
|
||||||
key_pair: KeyPair,
|
key_pair: KeyPair,
|
||||||
@ -36,7 +35,7 @@ impl PlainNodeKeyPair {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NodeKeyPair for PlainNodeKeyPair {
|
impl SigningKeyPair for PlainNodeKeyPair {
|
||||||
fn public(&self) -> &Public {
|
fn public(&self) -> &Public {
|
||||||
self.key_pair.public()
|
self.key_pair.public()
|
||||||
}
|
}
|
||||||
@ -48,60 +47,4 @@ impl NodeKeyPair for PlainNodeKeyPair {
|
|||||||
fn sign(&self, data: &H256) -> Result<Signature, EthKeyError> {
|
fn sign(&self, data: &H256) -> Result<Signature, EthKeyError> {
|
||||||
sign(self.key_pair.secret(), data)
|
sign(self.key_pair.secret(), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_shared_key(&self, peer_public: &Public) -> Result<KeyPair, EthKeyError> {
|
|
||||||
agree(self.key_pair.secret(), peer_public)
|
|
||||||
.map_err(|e| EthKeyError::Custom(e.to_string()))
|
|
||||||
.and_then(KeyPair::from_secret)
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "accounts")]
|
|
||||||
mod accounts {
|
|
||||||
use super::*;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use ethkey::Password;
|
|
||||||
use accounts::AccountProvider;
|
|
||||||
|
|
||||||
pub struct KeyStoreNodeKeyPair {
|
|
||||||
account_provider: Arc<AccountProvider>,
|
|
||||||
address: Address,
|
|
||||||
public: Public,
|
|
||||||
password: Password,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyStoreNodeKeyPair {
|
|
||||||
pub fn new(account_provider: Arc<AccountProvider>, address: Address, password: Password) -> Result<Self, EthKeyError> {
|
|
||||||
let public = account_provider.account_public(address.clone(), &password).map_err(|e| EthKeyError::Custom(format!("{}", e)))?;
|
|
||||||
Ok(KeyStoreNodeKeyPair {
|
|
||||||
account_provider,
|
|
||||||
address,
|
|
||||||
public,
|
|
||||||
password,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NodeKeyPair for KeyStoreNodeKeyPair {
|
|
||||||
fn public(&self) -> &Public {
|
|
||||||
&self.public
|
|
||||||
}
|
|
||||||
|
|
||||||
fn address(&self) -> Address {
|
|
||||||
public_to_address(&self.public)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sign(&self, data: &H256) -> Result<Signature, EthKeyError> {
|
|
||||||
self.account_provider.sign(self.address.clone(), Some(self.password.clone()), data.clone())
|
|
||||||
.map_err(|e| EthKeyError::Custom(format!("{}", e)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compute_shared_key(&self, peer_public: &Public) -> Result<KeyPair, EthKeyError> {
|
|
||||||
KeyPair::from_secret(self.account_provider.agree(self.address.clone(), Some(self.password.clone()), peer_public)
|
|
||||||
.map_err(|e| EthKeyError::Custom(format!("{}", e)))?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "accounts")]
|
|
||||||
pub use self::accounts::KeyStoreNodeKeyPair;
|
|
||||||
|
@ -16,23 +16,9 @@
|
|||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use futures::Future;
|
use futures::Future;
|
||||||
use crypto::publickey::{KeyPair, Signature, Error as EthKeyError};
|
|
||||||
use ethereum_types::{H256, Address};
|
|
||||||
use types::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, Requester,
|
use types::{Error, Public, ServerKeyId, MessageHash, EncryptedMessageSignature, RequestSignature, Requester,
|
||||||
EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId};
|
EncryptedDocumentKey, EncryptedDocumentKeyShadow, NodeId};
|
||||||
|
|
||||||
/// Node key pair.
|
|
||||||
pub trait NodeKeyPair: Send + Sync {
|
|
||||||
/// Public portion of key.
|
|
||||||
fn public(&self) -> &Public;
|
|
||||||
/// Address of key owner.
|
|
||||||
fn address(&self) -> Address;
|
|
||||||
/// Sign data with node key.
|
|
||||||
fn sign(&self, data: &H256) -> Result<Signature, EthKeyError>;
|
|
||||||
/// Compute shared key to encrypt channel between two nodes.
|
|
||||||
fn compute_shared_key(&self, peer_public: &Public) -> Result<KeyPair, EthKeyError>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Server key (SK) generator.
|
/// Server key (SK) generator.
|
||||||
pub trait ServerKeyGenerator {
|
pub trait ServerKeyGenerator {
|
||||||
/// Generate new SK.
|
/// Generate new SK.
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
|
||||||
// This file is part of Parity Ethereum.
|
|
||||||
|
|
||||||
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use std::sync::{Arc, Weak};
|
|
||||||
use bytes::Bytes;
|
|
||||||
use common_types::{
|
|
||||||
ids::BlockId,
|
|
||||||
transaction::{Transaction, SignedTransaction, Action},
|
|
||||||
};
|
|
||||||
use ethereum_types::Address;
|
|
||||||
use ethcore::client::Client;
|
|
||||||
use client_traits::{ChainInfo, Nonce};
|
|
||||||
use ethcore::miner::{Miner, MinerService};
|
|
||||||
use sync::SyncProvider;
|
|
||||||
use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED};
|
|
||||||
use {Error, NodeKeyPair, ContractAddress};
|
|
||||||
use registrar::RegistrarClient;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
/// 'Trusted' client weak reference.
|
|
||||||
pub struct TrustedClient {
|
|
||||||
/// This key server node key pair.
|
|
||||||
self_key_pair: Arc<dyn NodeKeyPair>,
|
|
||||||
/// Blockchain client.
|
|
||||||
client: Weak<Client>,
|
|
||||||
/// Sync provider.
|
|
||||||
sync: Weak<dyn SyncProvider>,
|
|
||||||
/// Miner service.
|
|
||||||
miner: Weak<Miner>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TrustedClient {
|
|
||||||
/// Create new trusted client.
|
|
||||||
pub fn new(self_key_pair: Arc<dyn NodeKeyPair>, client: Arc<Client>, sync: Arc<dyn SyncProvider>, miner: Arc<Miner>) -> Self {
|
|
||||||
TrustedClient {
|
|
||||||
self_key_pair,
|
|
||||||
client: Arc::downgrade(&client),
|
|
||||||
sync: Arc::downgrade(&sync),
|
|
||||||
miner: Arc::downgrade(&miner),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.is_major_syncing();
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Transact contract.
|
|
||||||
pub fn transact_contract(&self, contract: Address, tx_data: Bytes) -> Result<(), Error> {
|
|
||||||
let client = self.client.upgrade().ok_or_else(|| Error::Internal("cannot submit tx when client is offline".into()))?;
|
|
||||||
let miner = self.miner.upgrade().ok_or_else(|| Error::Internal("cannot submit tx when miner is offline".into()))?;
|
|
||||||
let engine = client.engine();
|
|
||||||
let transaction = Transaction {
|
|
||||||
nonce: client.latest_nonce(&self.self_key_pair.address()),
|
|
||||||
action: Action::Call(contract),
|
|
||||||
gas: miner.authoring_params().gas_range_target.0,
|
|
||||||
gas_price: miner.sensible_gas_price(),
|
|
||||||
value: Default::default(),
|
|
||||||
data: tx_data,
|
|
||||||
};
|
|
||||||
let chain_id = engine.signing_chain_id(&client.latest_env_info());
|
|
||||||
let signature = self.self_key_pair.sign(&transaction.hash(chain_id))?;
|
|
||||||
let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
|
|
||||||
miner.import_own_transaction(&*client, signed.into())
|
|
||||||
.map_err(|e| Error::Internal(format!("failed to import tx: {}", e)))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read contract address. If address source is registry, address only returned if current client state is
|
|
||||||
/// trusted. Address from registry is read from registry from block latest block with
|
|
||||||
/// REQUEST_CONFIRMATIONS_REQUIRED confirmations.
|
|
||||||
pub fn read_contract_address(
|
|
||||||
&self,
|
|
||||||
registry_name: &str,
|
|
||||||
address: &ContractAddress
|
|
||||||
) -> Option<Address> {
|
|
||||||
match *address {
|
|
||||||
ContractAddress::Address(ref address) => Some(address.clone()),
|
|
||||||
ContractAddress::Registry => self.get().and_then(|client|
|
|
||||||
get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED)
|
|
||||||
.and_then(|block| {
|
|
||||||
client.get_address(registry_name, BlockId::Hash(block))
|
|
||||||
.unwrap_or(None)
|
|
||||||
})
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use blockchain::ContractAddress;
|
||||||
use {bytes, ethereum_types};
|
use {bytes, ethereum_types};
|
||||||
|
|
||||||
/// Node id.
|
/// Node id.
|
||||||
@ -42,15 +43,6 @@ 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(crypto::publickey::Address),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Secret store configuration
|
/// Secret store configuration
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ServiceConfiguration {
|
pub struct ServiceConfiguration {
|
||||||
|
Loading…
Reference in New Issue
Block a user