// 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 . use std::sync::Arc; use parking_lot::RwLock; use common_types::filter::Filter; use ethabi::RawLog; use ethabi::FunctionOutputDecoder; use call_contract::CallContract; use ethcore::client::{Client, BlockChainClient, BlockId}; use ethkey::{Public, public_to_address}; use hash::keccak; use bytes::Bytes; use ethereum_types::{H256, U256, Address}; use listener::ApiMask; use listener::service_contract_listener::ServiceTask; use trusted_client::TrustedClient; use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED}; use {ServerKeyId, NodeKeyPair, ContractAddress}; use_contract!(service, "res/service.json"); /// Name of the general SecretStore contract in the registry. pub const SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service"; /// Name of the server key generation SecretStore contract in the registry. pub const SRV_KEY_GEN_SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service_srv_gen"; /// Name of the server key retrieval SecretStore contract in the registry. pub const SRV_KEY_RETR_SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service_srv_retr"; /// Name of the document key store SecretStore contract in the registry. pub const DOC_KEY_STORE_SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service_doc_store"; /// Name of the document key retrieval SecretStore contract in the registry. pub const DOC_KEY_SRETR_SERVICE_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_service_doc_sretr"; /// Server key generation has been requested. const SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME: &'static [u8] = &*b"ServerKeyGenerationRequested(bytes32,address,uint8)"; /// Server key retrieval has been requested. const SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME: &'static [u8] = &*b"ServerKeyRetrievalRequested(bytes32)"; /// Document key store has been requested. const DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME: &'static [u8] = &*b"DocumentKeyStoreRequested(bytes32,address,bytes,bytes)"; /// Document key common part retrieval has been requested. const DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME: &'static [u8] = &*b"DocumentKeyCommonRetrievalRequested(bytes32,address)"; /// Document key personal part retrieval has been requested. const DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME: &'static [u8] = &*b"DocumentKeyPersonalRetrievalRequested(bytes32,bytes)"; lazy_static! { pub static ref SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME_HASH: H256 = keccak(SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME); pub static ref SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME_HASH: H256 = keccak(SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME); pub static ref DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME_HASH: H256 = keccak(DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME); pub static ref DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH: H256 = keccak(DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME); pub static ref DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH: H256 = keccak(DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME); } /// Service contract trait. pub trait ServiceContract: Send + Sync { /// Update contract when new blocks are enacted. Returns true if contract is installed && up-to-date (i.e. chain is synced). fn update(&self) -> bool; /// Read recent contract logs. Returns topics of every entry. fn read_logs(&self) -> Box>; /// Publish generated key. fn read_pending_requests(&self) -> Box>; /// Publish generated server key. fn publish_generated_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public) -> Result<(), String>; /// Publish server key generation error. fn publish_server_key_generation_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String>; /// Publish retrieved server key. fn publish_retrieved_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public, threshold: usize) -> Result<(), String>; /// Publish server key retrieval error. fn publish_server_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String>; /// Publish stored document key. fn publish_stored_document_key(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String>; /// Publish document key store error. fn publish_document_key_store_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String>; /// Publish retrieved document key common. fn publish_retrieved_document_key_common(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: usize) -> Result<(), String>; /// Publish retrieved document key personal. fn publish_retrieved_document_key_personal(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<(), String>; /// Publish document key store error. fn publish_document_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String>; } /// On-chain service contract. pub struct OnChainServiceContract { /// Requests mask. mask: ApiMask, /// Blockchain client. client: TrustedClient, /// This node key pair. self_key_pair: Arc, /// Contract registry name (if any). name: String, /// Contract address source. address_source: ContractAddress, /// Contract. data: RwLock, } /// On-chain service contract data. struct ServiceData { /// Current contract address. pub contract_address: Option
, /// Last block we have read logs from. pub last_log_block: Option, } /// Pending requests iterator. struct PendingRequestsIterator Option<(bool, ServiceTask)>> { /// Pending request read function. read_request: F, /// Current request index. index: U256, /// Requests length. length: U256, } /// Server key generation related functions. struct ServerKeyGenerationService; /// Server key retrieval related functions. struct ServerKeyRetrievalService; /// Document key store related functions. struct DocumentKeyStoreService; /// Document key shadow retrievalrelated functions. struct DocumentKeyShadowRetrievalService; impl OnChainServiceContract { /// Create new on-chain service contract. pub fn new(mask: ApiMask, client: TrustedClient, name: String, address_source: ContractAddress, self_key_pair: Arc) -> Self { let contract = OnChainServiceContract { mask: mask, client: client, self_key_pair: self_key_pair, name: name, address_source: address_source, data: RwLock::new(ServiceData { contract_address: None, last_log_block: None, }), }; contract.update_contract_address(); contract } /// Send transaction to the service contract. fn send_contract_transaction(&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, P: FnOnce(&Client, &Address) -> Result { // only publish if contract address is set && client is online let client = match self.client.get() { Some(client) => client, None => return Err("trusted client is required to publish key".into()), }; // only publish key if contract waits for publication // failing is ok here - it could be that enough confirmations have been recevied // or key has been requested using HTTP API let self_address = public_to_address(self.self_key_pair.public()); if !is_response_required(&*client, origin, server_key_id, &self_address) { return Ok(()); } // prepare transaction data let transaction_data = prepare_tx(&*client, origin)?; // send transaction self.client.transact_contract( origin.clone(), transaction_data ).map_err(|e| format!("{}", e))?; trace!(target: "secretstore", "{}: transaction {} sent to service contract", self.self_key_pair.public(), tx_name); Ok(()) } /// Create task-specific pending requests iterator. fn create_pending_requests_iterator< C: 'static + Fn(&Client, &Address, &BlockId) -> Result, R: 'static + Fn(&NodeKeyPair, &Client, &Address, &BlockId, U256) -> Result<(bool, ServiceTask), String> >(&self, client: Arc, contract_address: &Address, block: &BlockId, get_count: C, read_item: R) -> Box> { get_count(&*client, contract_address, block) .map(|count| { let client = client.clone(); let self_key_pair = self.self_key_pair.clone(); let contract_address = contract_address.clone(); let block = block.clone(); Box::new(PendingRequestsIterator { read_request: move |index| read_item(&*self_key_pair, &*client, &contract_address, &block, index) .map_err(|error| { warn!(target: "secretstore", "{}: reading pending request failed: {}", self_key_pair.public(), error); error }) .ok(), index: 0.into(), length: count, }) as Box> }) .map_err(|error| { warn!(target: "secretstore", "{}: creating pending requests iterator failed: {}", self.self_key_pair.public(), error); error }) .ok() .unwrap_or_else(|| Box::new(::std::iter::empty())) } /// Update service contract address. fn update_contract_address(&self) -> bool { let contract_address = self.client.read_contract_address(self.name.clone(), &self.address_source); let mut data = self.data.write(); if contract_address != data.contract_address { trace!(target: "secretstore", "{}: installing {} service contract from address {:?}", self.self_key_pair.public(), self.name, contract_address); data.contract_address = contract_address; } data.contract_address.is_some() } } impl ServiceContract for OnChainServiceContract { fn update(&self) -> bool { self.update_contract_address() && self.client.get().is_some() } fn read_logs(&self) -> Box> { let client = match self.client.get() { Some(client) => client, None => { warn!(target: "secretstore", "{}: client is offline during read_logs call", self.self_key_pair.public()); return Box::new(::std::iter::empty()); }, }; // prepare range of blocks to read logs from let (address, first_block, last_block) = { let mut data = self.data.write(); let address = match data.contract_address { Some(address) => address, None => return Box::new(::std::iter::empty()), // no contract installed }; let confirmed_block = match get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED) { Some(confirmed_block) => confirmed_block, 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()); (address, first_block, 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]), topics: vec![Some(mask_topics(&self.mask))], limit: None, }).unwrap_or_default(); Box::new(request_logs.into_iter() .filter_map(|log| { let raw_log: RawLog = (log.entry.topics.into_iter().map(|t| t.0.into()).collect(), log.entry.data).into(); if raw_log.topics[0] == *SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME_HASH { ServerKeyGenerationService::parse_log(&address, raw_log) } else if raw_log.topics[0] == *SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME_HASH { ServerKeyRetrievalService::parse_log(&address, raw_log) } else if raw_log.topics[0] == *DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME_HASH { DocumentKeyStoreService::parse_log(&address, raw_log) } else if raw_log.topics[0] == *DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH { DocumentKeyShadowRetrievalService::parse_common_request_log(&address, raw_log) } else if raw_log.topics[0] == *DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH { DocumentKeyShadowRetrievalService::parse_personal_request_log(&address, raw_log) } else { Err("unknown type of log entry".into()) } .map_err(|error| { warn!(target: "secretstore", "{}: error parsing log entry from service contract: {}", self.self_key_pair.public(), error); error }) .ok() }).collect::>().into_iter()) } fn read_pending_requests(&self) -> Box> { let client = match self.client.get() { Some(client) => client, None => return Box::new(::std::iter::empty()), }; // we only need requests that are here for more than REQUEST_CONFIRMATIONS_REQUIRED blocks // => we're reading from Latest - (REQUEST_CONFIRMATIONS_REQUIRED + 1) block let data = self.data.read(); match data.contract_address { None => Box::new(::std::iter::empty()), Some(contract_address) => get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED + 1) .map(|b| { let block = BlockId::Hash(b); let iter = match self.mask.server_key_generation_requests { true => Box::new(self.create_pending_requests_iterator(client.clone(), &contract_address, &block, &ServerKeyGenerationService::read_pending_requests_count, &ServerKeyGenerationService::read_pending_request)) as Box>, false => Box::new(::std::iter::empty()), }; let iter = match self.mask.server_key_retrieval_requests { true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &contract_address, &block, &ServerKeyRetrievalService::read_pending_requests_count, &ServerKeyRetrievalService::read_pending_request))), false => iter, }; let iter = match self.mask.document_key_store_requests { true => Box::new(iter.chain(self.create_pending_requests_iterator(client.clone(), &contract_address, &block, &DocumentKeyStoreService::read_pending_requests_count, &DocumentKeyStoreService::read_pending_request))), false => iter, }; let iter = match self.mask.document_key_shadow_retrieval_requests { true => Box::new(iter.chain(self.create_pending_requests_iterator(client, &contract_address, &block, &DocumentKeyShadowRetrievalService::read_pending_requests_count, &DocumentKeyShadowRetrievalService::read_pending_request))), false => iter }; iter }) .unwrap_or_else(|| Box::new(::std::iter::empty())) } } fn publish_generated_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public) -> Result<(), String> { self.send_contract_transaction("publish_generated_server_key", origin, server_key_id, ServerKeyGenerationService::is_response_required, |_, _| Ok(ServerKeyGenerationService::prepare_pubish_tx_data(server_key_id, &server_key))) } fn publish_server_key_generation_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { self.send_contract_transaction("publish_server_key_generation_error", origin, server_key_id, ServerKeyGenerationService::is_response_required, |_, _| Ok(ServerKeyGenerationService::prepare_error_tx_data(server_key_id))) } fn publish_retrieved_server_key(&self, origin: &Address, server_key_id: &ServerKeyId, server_key: Public, threshold: usize) -> Result<(), String> { let threshold = serialize_threshold(threshold)?; self.send_contract_transaction("publish_retrieved_server_key", origin, server_key_id, ServerKeyRetrievalService::is_response_required, |_, _| Ok(ServerKeyRetrievalService::prepare_pubish_tx_data(server_key_id, server_key, threshold))) } fn publish_server_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { self.send_contract_transaction("publish_server_key_retrieval_error", origin, server_key_id, ServerKeyRetrievalService::is_response_required, |_, _| Ok(ServerKeyRetrievalService::prepare_error_tx_data(server_key_id))) } fn publish_stored_document_key(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { self.send_contract_transaction("publish_stored_document_key", origin, server_key_id, DocumentKeyStoreService::is_response_required, |_, _| Ok(DocumentKeyStoreService::prepare_pubish_tx_data(server_key_id))) } fn publish_document_key_store_error(&self, origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { self.send_contract_transaction("publish_document_key_store_error", origin, server_key_id, DocumentKeyStoreService::is_response_required, |_, _| Ok(DocumentKeyStoreService::prepare_error_tx_data(server_key_id))) } fn publish_retrieved_document_key_common(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: usize) -> Result<(), String> { let threshold = serialize_threshold(threshold)?; self.send_contract_transaction("publish_retrieved_document_key_common", origin, server_key_id, |client, contract_address, server_key_id, key_server| DocumentKeyShadowRetrievalService::is_response_required(client, contract_address, server_key_id, requester, key_server), |_, _| Ok(DocumentKeyShadowRetrievalService::prepare_pubish_common_tx_data(server_key_id, requester, common_point, threshold)) ) } fn publish_retrieved_document_key_personal(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<(), String> { self.send_contract_transaction("publish_retrieved_document_key_personal", origin, server_key_id, |_, _, _, _| true, move |client, address| DocumentKeyShadowRetrievalService::prepare_pubish_personal_tx_data(client, address, server_key_id, requester, participants, decrypted_secret, shadow) ) } fn publish_document_key_retrieval_error(&self, origin: &Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String> { self.send_contract_transaction("publish_document_key_retrieval_error", origin, server_key_id, |client, contract_address, server_key_id, key_server| DocumentKeyShadowRetrievalService::is_response_required(client, contract_address, server_key_id, requester, key_server), |_, _| Ok(DocumentKeyShadowRetrievalService::prepare_error_tx_data(server_key_id, requester)) ) } } impl Iterator for PendingRequestsIterator where F: Fn(U256) -> Option<(bool, ServiceTask)> { type Item = (bool, ServiceTask); fn next(&mut self) -> Option<(bool, ServiceTask)> { if self.index >= self.length { return None; } let index = self.index.clone(); self.index = self.index + 1; (self.read_request)(index) } } /// Returns vector of logs topics to listen to. pub fn mask_topics(mask: &ApiMask) -> Vec { let mut topics = Vec::new(); if mask.server_key_generation_requests { topics.push(*SERVER_KEY_GENERATION_REQUESTED_EVENT_NAME_HASH); } if mask.server_key_retrieval_requests { topics.push(*SERVER_KEY_RETRIEVAL_REQUESTED_EVENT_NAME_HASH); } if mask.document_key_store_requests { topics.push(*DOCUMENT_KEY_STORE_REQUESTED_EVENT_NAME_HASH); } if mask.document_key_shadow_retrieval_requests { topics.push(*DOCUMENT_KEY_COMMON_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH); topics.push(*DOCUMENT_KEY_PERSONAL_PART_RETRIEVAL_REQUESTED_EVENT_NAME_HASH); } topics } impl ServerKeyGenerationService { /// Parse request log entry. pub fn parse_log(origin: &Address, raw_log: RawLog) -> Result { match service::events::server_key_generation_requested::parse_log(raw_log) { Ok(l) => Ok(ServiceTask::GenerateServerKey(origin.clone(), l.server_key_id, l.author, parse_threshold(l.threshold)?)), Err(e) => Err(format!("{}", e)), } } /// 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 { // 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); match client.call_contract(BlockId::Latest, *contract_address, encoded) { Err(_) => true, Ok(data) => decoder.decode(&data).unwrap_or(true) } } /// Prepare publish key transaction data. pub fn prepare_pubish_tx_data(server_key_id: &ServerKeyId, server_key_public: &Public) -> Bytes { service::functions::server_key_generated::encode_input(*server_key_id, server_key_public.to_vec()) } /// Prepare error transaction data. pub fn prepare_error_tx_data(server_key_id: &ServerKeyId) -> Bytes { service::functions::server_key_generation_error::encode_input(*server_key_id) } /// Read pending requests count. fn read_pending_requests_count(client: &Client, contract_address: &Address, block: &BlockId) -> Result { let (encoded, decoder) = service::functions::server_key_generation_requests_count::call(); decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string()) } /// Read pending request. fn read_pending_request(self_key_pair: &NodeKeyPair, client: &Client, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> { let self_address = public_to_address(self_key_pair.public()); let (encoded, decoder) = service::functions::get_server_key_generation_request::call(index); let (server_key_id, author, threshold) = decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string())?; let threshold = parse_threshold(threshold)?; let (encoded, decoder) = service::functions::is_server_key_generation_response_required::call(server_key_id, self_address); let not_confirmed = decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string())?; let task = ServiceTask::GenerateServerKey( contract_address.clone(), server_key_id, author, threshold, ); Ok((not_confirmed, task)) } } impl ServerKeyRetrievalService { /// Parse request log entry. pub fn parse_log(origin: &Address, raw_log: RawLog) -> Result { match service::events::server_key_retrieval_requested::parse_log(raw_log) { Ok(l) => Ok(ServiceTask::RetrieveServerKey(*origin, l.server_key_id)), Err(e) => Err(e.to_string()) } } /// 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 { // 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); match client.call_contract(BlockId::Latest, *contract_address, encoded) { Err(_) => true, Ok(data) => decoder.decode(&data).unwrap_or(true) } } /// Prepare publish key transaction data. pub fn prepare_pubish_tx_data(server_key_id: &ServerKeyId, server_key_public: Public, threshold: U256) -> Bytes { service::functions::server_key_retrieved::encode_input(*server_key_id, server_key_public.to_vec(), threshold) } /// Prepare error transaction data. pub fn prepare_error_tx_data(server_key_id: &ServerKeyId) -> Bytes { service::functions::server_key_retrieval_error::encode_input(*server_key_id) } /// Read pending requests count. fn read_pending_requests_count(client: &Client, contract_address: &Address, block: &BlockId) -> Result { let (encoded, decoder) = service::functions::server_key_retrieval_requests_count::call(); decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string()) } /// Read pending request. fn read_pending_request(self_key_pair: &NodeKeyPair, client: &Client, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> { let self_address = public_to_address(self_key_pair.public()); let (encoded, decoder) = service::functions::get_server_key_retrieval_request::call(index); let server_key_id = decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string())?; let (encoded, decoder) = service::functions::is_server_key_retrieval_response_required::call(server_key_id, self_address); let not_confirmed = decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string())?; let task = ServiceTask::RetrieveServerKey( *contract_address, server_key_id, ); Ok((not_confirmed, task)) } } impl DocumentKeyStoreService { /// Parse request log entry. pub fn parse_log(origin: &Address, raw_log: RawLog) -> Result { match service::events::document_key_store_requested::parse_log(raw_log) { Ok(l) => Ok(ServiceTask::StoreDocumentKey(origin.clone(), l.server_key_id, l.author, (*l.common_point).into(), (*l.encrypted_point).into())), Err(e) => Err(format!("{}", e)), } } /// 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 { // 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); match client.call_contract(BlockId::Latest, *contract_address, encoded) { Err(_) => true, Ok(data) => decoder.decode(&data).unwrap_or(true) } } /// Prepare publish key transaction data. pub fn prepare_pubish_tx_data(server_key_id: &ServerKeyId) -> Bytes { service::functions::document_key_stored::encode_input(*server_key_id) } /// Prepare error transaction data. pub fn prepare_error_tx_data(server_key_id: &ServerKeyId) -> Bytes { service::functions::document_key_store_error::encode_input(*server_key_id) } /// Read pending requests count. fn read_pending_requests_count(client: &Client, contract_address: &Address, block: &BlockId) -> Result { let (encoded, decoder) = service::functions::document_key_store_requests_count::call(); decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string()) } /// Read pending request. fn read_pending_request(self_key_pair: &NodeKeyPair, client: &Client, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> { let self_address = public_to_address(self_key_pair.public()); 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)?) .map_err(|e| e.to_string())?; let (encoded, decoder) = service::functions::is_document_key_store_response_required::call(server_key_id, self_address); let not_confirmed = decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string())?; let task = ServiceTask::StoreDocumentKey( *contract_address, server_key_id, author, Public::from_slice(&common_point), Public::from_slice(&encrypted_point), ); Ok((not_confirmed, task)) } } impl DocumentKeyShadowRetrievalService { /// Parse common request log entry. pub fn parse_common_request_log(origin: &Address, raw_log: RawLog) -> Result { match service::events::document_key_common_retrieval_requested::parse_log(raw_log) { Ok(l) => Ok(ServiceTask::RetrieveShadowDocumentKeyCommon(origin.clone(), l.server_key_id, l.requester)), Err(e) => Err(e.to_string()) } } /// Parse personal request log entry. pub fn parse_personal_request_log(origin: &Address, raw_log: RawLog) -> Result { match service::events::document_key_personal_retrieval_requested::parse_log(raw_log) { Ok(l) => Ok(ServiceTask::RetrieveShadowDocumentKeyPersonal(origin.clone(), l.server_key_id, (*l.requester_public).into())), Err(e) => Err(e.to_string()) } } /// 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 { // 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); match client.call_contract(BlockId::Latest, *contract_address, encoded) { Err(_) => true, Ok(data) => decoder.decode(&data).unwrap_or(true) } } /// Prepare publish common key transaction data. pub fn prepare_pubish_common_tx_data(server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: U256) -> Bytes { service::functions::document_key_common_retrieved::encode_input(*server_key_id, *requester, common_point.to_vec(), threshold) } /// 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 { let mut participants_mask = U256::default(); for participant in participants { let participant_index = Self::map_key_server_address(client, contract_address, participant.clone()) .map_err(|e| format!("Error searching for {} participant: {}", participant, e))?; participants_mask = participants_mask | (U256::one() << participant_index); } Ok(service::functions::document_key_personal_retrieved::encode_input( *server_key_id, *requester, participants_mask, decrypted_secret.to_vec(), shadow )) } /// Prepare error transaction data. pub fn prepare_error_tx_data(server_key_id: &ServerKeyId, requester: &Address) -> Bytes { service::functions::document_key_shadow_retrieval_error::encode_input(*server_key_id, *requester) } /// Read pending requests count. fn read_pending_requests_count(client: &Client, contract_address: &Address, block: &BlockId) -> Result { let (encoded, decoder) = service::functions::document_key_shadow_retrieval_requests_count::call(); decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string()) } /// Read pending request. fn read_pending_request(self_key_pair: &NodeKeyPair, client: &Client, contract_address: &Address, block: &BlockId, index: U256) -> Result<(bool, ServiceTask), String> { let self_address = public_to_address(self_key_pair.public()); let (encoded, decoder) = service::functions::get_document_key_shadow_retrieval_request::call(index); let (server_key_id, requester, is_common_retrieval_completed) = decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string())?; let requester = Public::from_slice(&requester); let (encoded, decoder) = service::functions::is_document_key_shadow_retrieval_response_required::call(server_key_id, public_to_address(&requester), self_address); let not_confirmed = decoder.decode(&client.call_contract(*block, *contract_address, encoded)?) .map_err(|e| e.to_string())?; let task = match is_common_retrieval_completed { true => ServiceTask::RetrieveShadowDocumentKeyPersonal( *contract_address, server_key_id, requester, ), false => ServiceTask::RetrieveShadowDocumentKeyCommon( *contract_address, server_key_id, public_to_address(&requester), ), }; Ok((not_confirmed, task)) } /// Map from key server address to key server index. fn map_key_server_address(client: &Client, contract_address: &Address, key_server: Address) -> Result { // 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 index = decoder.decode(&client.call_contract(BlockId::Latest, *contract_address, encoded)?) .map_err(|e| e.to_string())?; if index > u8::max_value().into() { Err(format!("key server index is too big: {}", index)) } else { let index: u32 = index.into(); Ok(index as u8) } } } /// Parse threshold (we only supposrt 256 KS at max). fn parse_threshold(threshold: U256) -> Result { let threshold_num = threshold.low_u64(); if threshold != threshold_num.into() || threshold_num >= ::std::u8::MAX as u64 { return Err(format!("invalid threshold to use in service contract: {}", threshold)); } Ok(threshold_num as usize) } /// Serialize threshold (we only support 256 KS at max). fn serialize_threshold(threshold: usize) -> Result { if threshold > ::std::u8::MAX as usize { return Err(format!("invalid threshold to use in service contract: {}", threshold)); } Ok(threshold.into()) } #[cfg(test)] pub mod tests { use parking_lot::Mutex; use bytes::Bytes; use ethkey::Public; use ethereum_types::Address; use listener::service_contract_listener::ServiceTask; use {ServerKeyId}; use super::ServiceContract; #[derive(Default)] pub struct DummyServiceContract { pub is_actual: bool, pub logs: Vec, pub pending_requests: Vec<(bool, ServiceTask)>, pub generated_server_keys: Mutex>, pub server_keys_generation_failures: Mutex>, pub retrieved_server_keys: Mutex>, pub server_keys_retrieval_failures: Mutex>, pub stored_document_keys: Mutex>, pub document_keys_store_failures: Mutex>, pub common_shadow_retrieved_document_keys: Mutex>, pub personal_shadow_retrieved_document_keys: Mutex, Public, Bytes)>>, pub document_keys_shadow_retrieval_failures: Mutex>, } impl ServiceContract for DummyServiceContract { fn update(&self) -> bool { true } fn read_logs(&self) -> Box> { Box::new(self.logs.clone().into_iter()) } fn read_pending_requests(&self) -> Box> { Box::new(self.pending_requests.clone().into_iter()) } fn publish_generated_server_key(&self, _origin: &Address, server_key_id: &ServerKeyId, server_key: Public) -> Result<(), String> { self.generated_server_keys.lock().push((server_key_id.clone(), server_key.clone())); Ok(()) } fn publish_server_key_generation_error(&self, _origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { self.server_keys_generation_failures.lock().push(server_key_id.clone()); Ok(()) } fn publish_retrieved_server_key(&self, _origin: &Address, server_key_id: &ServerKeyId, server_key: Public, threshold: usize) -> Result<(), String> { self.retrieved_server_keys.lock().push((server_key_id.clone(), server_key.clone(), threshold)); Ok(()) } fn publish_server_key_retrieval_error(&self, _origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { self.server_keys_retrieval_failures.lock().push(server_key_id.clone()); Ok(()) } fn publish_stored_document_key(&self, _origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { self.stored_document_keys.lock().push(server_key_id.clone()); Ok(()) } fn publish_document_key_store_error(&self, _origin: &Address, server_key_id: &ServerKeyId) -> Result<(), String> { self.document_keys_store_failures.lock().push(server_key_id.clone()); Ok(()) } fn publish_retrieved_document_key_common(&self, _origin: &Address, server_key_id: &ServerKeyId, requester: &Address, common_point: Public, threshold: usize) -> Result<(), String> { self.common_shadow_retrieved_document_keys.lock().push((server_key_id.clone(), requester.clone(), common_point.clone(), threshold)); Ok(()) } fn publish_retrieved_document_key_personal(&self, _origin: &Address, server_key_id: &ServerKeyId, requester: &Address, participants: &[Address], decrypted_secret: Public, shadow: Bytes) -> Result<(), String> { self.personal_shadow_retrieved_document_keys.lock().push((server_key_id.clone(), requester.clone(), participants.iter().cloned().collect(), decrypted_secret, shadow)); Ok(()) } fn publish_document_key_retrieval_error(&self, _origin: &Address, server_key_id: &ServerKeyId, requester: &Address) -> Result<(), String> { self.document_keys_shadow_retrieval_failures.lock().push((server_key_id.clone(), requester.clone())); Ok(()) } } }