openethereum/secret-store/src/trusted_client.rs
Toby Dimmick 79a17dedd0 Deduplicate registrar contract & calling logic (#11110)
* Rename RegistryInfo -> RegistryInfoDeprecated

* Add BlockId parameter to Registrar::get_address and RegistrarClient::call_contract

* Remove RegistrarClient::Call (use async for now); add RegistrarClient::get_address

* Remove Registrar type in favour of naked trait

* Use CallContract trait bound instead of separate call_contract method

* Make RegistrarClient::get_address and URLHint::resolve synchronous

* RegistrarClient::get_address: return check if address is zero

* Modify RegistryInfo::registry_address to take &str

* return Result from RegistryInfo::registry_address

* Replace RegistryInfo with RegistrarClient

- Modifed RegistrarClient::registrar_address to return Option
- Removed BlockChainClient::registrar_address

* Fix other build configs

* Fix unit test builds

* Remove local RegistrarClient type from run::execute_impl

* Remove registrar.json from ethcore

* Formatting/line breaks

* Update RegistrarClient docs, remove explicit lifetime

* Weak ref to ethcore client from hash fetch client

* Fix unit tests
2019-10-03 15:15:25 +02:00

115 lines
4.0 KiB
Rust

// 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)
})
),
}
}
}