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
This commit is contained in:
parent
0c0f965354
commit
79a17dedd0
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -510,6 +510,7 @@ dependencies = [
|
||||
"ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kvdb 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"registrar 0.0.1",
|
||||
"stats 0.1.0",
|
||||
"trace 0.1.0",
|
||||
"vm 0.1.0",
|
||||
@ -1014,9 +1015,6 @@ dependencies = [
|
||||
"criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"engine 0.1.0",
|
||||
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi-contract 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi-derive 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethash 1.12.0",
|
||||
"ethcore-accounts 0.1.0",
|
||||
"ethcore-blockchain 0.1.0",
|
||||
@ -1052,6 +1050,7 @@ dependencies = [
|
||||
"pod 0.1.0",
|
||||
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"registrar 0.0.1",
|
||||
"rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1270,6 +1269,7 @@ dependencies = [
|
||||
"parity-util-mem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"price-info 1.12.0",
|
||||
"registrar 0.0.1",
|
||||
"rlp 0.4.2 (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.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1368,6 +1368,7 @@ dependencies = [
|
||||
"parity-util-mem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"patricia-trie-ethereum 0.1.0",
|
||||
"registrar 0.0.1",
|
||||
"rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rlp_derive 0.1.0",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -1415,6 +1416,7 @@ dependencies = [
|
||||
"parity-runtime 0.1.0",
|
||||
"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)",
|
||||
"registrar 0.0.1",
|
||||
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@ -2966,7 +2968,6 @@ dependencies = [
|
||||
"ethcore 1.12.0",
|
||||
"ethcore-accounts 0.1.0",
|
||||
"ethcore-blockchain 0.1.0",
|
||||
"ethcore-call-contract 0.1.0",
|
||||
"ethcore-db 0.1.0",
|
||||
"ethcore-io 1.12.0",
|
||||
"ethcore-light 1.12.0",
|
||||
@ -3032,9 +3033,11 @@ dependencies = [
|
||||
name = "parity-hash-fetch"
|
||||
version = "1.12.0"
|
||||
dependencies = [
|
||||
"common-types 0.1.0",
|
||||
"ethabi 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi-contract 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi-derive 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-call-contract 0.1.0",
|
||||
"ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fake-fetch 0.0.1",
|
||||
"fetch 0.1.0",
|
||||
@ -3854,10 +3857,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
name = "registrar"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"common-types 0.1.0",
|
||||
"ethabi 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi-contract 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi-derive 8.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-call-contract 0.1.0",
|
||||
"keccak-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
|
@ -21,7 +21,6 @@ engine = { path = "ethcore/engine" }
|
||||
ethcore = { path = "ethcore", features = ["parity"] }
|
||||
ethcore-accounts = { path = "accounts", optional = true }
|
||||
ethcore-blockchain = { path = "ethcore/blockchain" }
|
||||
ethcore-call-contract = { path = "ethcore/call-contract"}
|
||||
ethcore-db = { path = "ethcore/db" }
|
||||
ethcore-io = { path = "util/io" }
|
||||
ethcore-light = { path = "ethcore/light" }
|
||||
|
@ -15,9 +15,6 @@ client-traits = { path = "./client-traits" }
|
||||
common-types = { path = "types" }
|
||||
engine = { path = "./engine" }
|
||||
env_logger = { version = "0.5", optional = true }
|
||||
ethabi = "8.0"
|
||||
ethabi-contract = "8.0"
|
||||
ethabi-derive = "8.0"
|
||||
ethash = { path = "../ethash", optional = true }
|
||||
ethjson = { path = "../json", optional = true }
|
||||
ethkey = { path = "../accounts/ethkey", optional = true }
|
||||
@ -50,6 +47,7 @@ trie-db = "0.15.0"
|
||||
patricia-trie-ethereum = { path = "../util/patricia-trie-ethereum" }
|
||||
rand = "0.6"
|
||||
rayon = "1.1"
|
||||
registrar = { path = "../util/registrar" }
|
||||
rlp = "0.4.0"
|
||||
rustc-hex = "2"
|
||||
serde = "1.0"
|
||||
|
@ -14,7 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Provides CallContract and RegistryInfo traits
|
||||
//! Provides CallContract trait
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::Address;
|
||||
@ -23,11 +23,10 @@ use types::ids::BlockId;
|
||||
/// Provides `call_contract` method
|
||||
pub trait CallContract {
|
||||
/// Like `call`, but with various defaults. Designed to be used for calling contracts.
|
||||
fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String>;
|
||||
}
|
||||
|
||||
/// Provides information on a blockchain service and it's registry
|
||||
pub trait RegistryInfo {
|
||||
/// Get the address of a particular blockchain service, if available.
|
||||
fn registry_address(&self, name: String, block: BlockId) -> Option<Address>;
|
||||
fn call_contract(
|
||||
&self,
|
||||
block_id: BlockId,
|
||||
address: Address,
|
||||
data: Bytes
|
||||
) -> Result<Bytes, String>;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ ethcore-db = { path = "../db" }
|
||||
ethcore-miner = { path = "../../miner" }
|
||||
ethereum-types = "0.6.0"
|
||||
kvdb = "0.1"
|
||||
registrar = { path = "../../util/registrar" }
|
||||
stats = { path = "../../util/stats" }
|
||||
trace = { path = "../trace" }
|
||||
vm = { path = "../vm" }
|
||||
|
@ -22,7 +22,8 @@ use std::{
|
||||
use account_state::state::StateInfo;
|
||||
use blockchain::BlockProvider;
|
||||
use bytes::Bytes;
|
||||
use call_contract::{CallContract, RegistryInfo};
|
||||
use call_contract::CallContract;
|
||||
use registrar::RegistrarClient;
|
||||
use common_types::{
|
||||
basic_account::BasicAccount,
|
||||
block_status::BlockStatus,
|
||||
@ -218,8 +219,10 @@ pub trait BadBlocks {
|
||||
|
||||
|
||||
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
||||
pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContract + RegistryInfo + ImportBlock
|
||||
+ IoClient + BadBlocks {
|
||||
pub trait BlockChainClient:
|
||||
Sync + Send + AccountData + BlockChain + CallContract + RegistrarClient
|
||||
+ ImportBlock + IoClient + BadBlocks
|
||||
{
|
||||
/// Look up the block number for the given block ID.
|
||||
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
|
||||
|
||||
@ -393,9 +396,6 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra
|
||||
|
||||
/// Schedule state-altering transaction to be executed on the next pending block.
|
||||
fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error>;
|
||||
|
||||
/// Get the address of the registry itself.
|
||||
fn registrar_address(&self) -> Option<Address>;
|
||||
}
|
||||
|
||||
/// resets the blockchain
|
||||
|
@ -36,6 +36,7 @@ parity-crypto = "0.4.0"
|
||||
parking_lot = "0.9"
|
||||
trie-db = "0.15.0"
|
||||
patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" }
|
||||
registrar = { path = "../../util/registrar" }
|
||||
rlp = "0.4.0"
|
||||
rlp_derive = { path = "../../util/rlp-derive" }
|
||||
rustc-hex = "1.0"
|
||||
|
@ -19,7 +19,8 @@
|
||||
use std::sync::Arc;
|
||||
use parking_lot::RwLock;
|
||||
use ethereum_types::{H256, Address};
|
||||
use call_contract::{CallContract, RegistryInfo};
|
||||
use call_contract::CallContract;
|
||||
use registrar::RegistrarClient;
|
||||
use types::ids::BlockId;
|
||||
use ethabi::FunctionOutputDecoder;
|
||||
|
||||
@ -53,13 +54,13 @@ pub trait KeyProvider: Send + Sync + 'static {
|
||||
}
|
||||
|
||||
/// Secret Store keys provider
|
||||
pub struct SecretStoreKeys<C> where C: CallContract + RegistryInfo + Send + Sync + 'static {
|
||||
pub struct SecretStoreKeys<C> where C: CallContract + RegistrarClient + Send + Sync + 'static {
|
||||
client: Arc<C>,
|
||||
key_server_account: Option<Address>,
|
||||
keys_acl_contract: RwLock<Option<Address>>,
|
||||
}
|
||||
|
||||
impl<C> SecretStoreKeys<C> where C: CallContract + RegistryInfo + Send + Sync + 'static {
|
||||
impl<C> SecretStoreKeys<C> where C: CallContract + RegistrarClient + Send + Sync + 'static {
|
||||
/// Create provider
|
||||
pub fn new(client: Arc<C>, key_server_account: Option<Address>) -> Self {
|
||||
SecretStoreKeys {
|
||||
@ -70,7 +71,9 @@ impl<C> SecretStoreKeys<C> where C: CallContract + RegistryInfo + Send + Sync +
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> KeyProvider for SecretStoreKeys<C> where C: CallContract + RegistryInfo + Send + Sync + 'static {
|
||||
impl<C> KeyProvider for SecretStoreKeys<C>
|
||||
where C: CallContract + RegistrarClient + Send + Sync + 'static
|
||||
{
|
||||
fn key_server_account(&self) -> Option<Address> {
|
||||
self.key_server_account
|
||||
}
|
||||
@ -92,7 +95,11 @@ impl<C> KeyProvider for SecretStoreKeys<C> where C: CallContract + RegistryInfo
|
||||
}
|
||||
|
||||
fn update_acl_contract(&self) {
|
||||
let contract_address = self.client.registry_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.into(), BlockId::Latest);
|
||||
let contract_address = self.client.get_address(
|
||||
ACL_CHECKER_CONTRACT_REGISTRY_NAME,
|
||||
BlockId::Latest
|
||||
).unwrap_or(None);
|
||||
|
||||
if *self.keys_acl_contract.read() != contract_address {
|
||||
trace!(target: "privatetx", "Configuring for ACL checker contract from address {:?}",
|
||||
contract_address);
|
||||
@ -141,6 +148,7 @@ mod tests {
|
||||
use ethkey::{Secret, KeyPair};
|
||||
use bytes::Bytes;
|
||||
use super::*;
|
||||
use registrar::RegistrarClient;
|
||||
|
||||
struct DummyRegistryClient {
|
||||
registry_address: Option<Address>,
|
||||
@ -154,12 +162,25 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistryInfo for DummyRegistryClient {
|
||||
fn registry_address(&self, _name: String, _block: BlockId) -> Option<Address> { self.registry_address }
|
||||
impl RegistrarClient for DummyRegistryClient {
|
||||
fn registrar_address(&self) -> Option<Address> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_address(&self, _name: &str, _block: BlockId) -> Result<Option<Address>, String> {
|
||||
Ok(self.registry_address)
|
||||
}
|
||||
}
|
||||
|
||||
impl CallContract for DummyRegistryClient {
|
||||
fn call_contract(&self, _id: BlockId, _address: Address, _data: Bytes) -> Result<Bytes, String> { Ok(vec![]) }
|
||||
fn call_contract(
|
||||
&self,
|
||||
_block_id: BlockId,
|
||||
_address: Address,
|
||||
_data: Bytes
|
||||
) -> Result<Bytes, String> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -51,6 +51,7 @@ extern crate parity_crypto as crypto;
|
||||
extern crate parking_lot;
|
||||
extern crate trie_db as trie;
|
||||
extern crate patricia_trie_ethereum as ethtrie;
|
||||
extern crate registrar;
|
||||
extern crate rlp;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
@ -1,21 +0,0 @@
|
||||
[
|
||||
{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_name","type":"string"}],"name":"confirmReverse","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"bytes32"}],"name":"set","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"drop","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||
{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"setFee","outputs":[],"type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_to","type":"address"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||
{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"type":"function"},
|
||||
{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserved","outputs":[{"name":"reserved","type":"bool"}],"type":"function"},
|
||||
{"constant":false,"inputs":[],"name":"drain","outputs":[],"type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"proposeReverse","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||
{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"type":"function"},
|
||||
{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"type":"function"},
|
||||
{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"type":"function"},
|
||||
{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"reverse","outputs":[{"name":"","type":"string"}],"type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"uint256"}],"name":"setUint","outputs":[{"name":"success","type":"bool"}],"type":"function"},
|
||||
{"constant":false,"inputs":[],"name":"removeReverse","outputs":[],"type":"function"},
|
||||
{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"address"}],"name":"setAddress","outputs":[{"name":"success","type":"bool"}],"type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"Drained","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"amount","type":"uint256"}],"name":"FeeChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"owner","type":"address"}],"name":"Reserved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"oldOwner","type":"address"},{"indexed":true,"name":"newOwner","type":"address"}],"name":"Transferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"owner","type":"address"}],"name":"Dropped","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"bytes32"},{"indexed":true,"name":"owner","type":"address"},{"indexed":true,"name":"key","type":"string"}],"name":"DataChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":true,"name":"reverse","type":"address"}],"name":"ReverseProposed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":true,"name":"reverse","type":"address"}],"name":"ReverseConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"name","type":"string"},{"indexed":true,"name":"reverse","type":"address"}],"name":"ReverseRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"old","type":"address"},{"indexed":true,"name":"current","type":"address"}],"name":"NewOwner","type":"event"}
|
||||
]
|
@ -51,7 +51,7 @@ use blockchain::{
|
||||
TransactionAddress,
|
||||
TreeRoute
|
||||
};
|
||||
use call_contract::{CallContract, RegistryInfo};
|
||||
use call_contract::CallContract;
|
||||
use client::{
|
||||
bad_blocks, BlockProducer, BroadcastProposalBlock, Call,
|
||||
ClientConfig, EngineInfo, ImportSealedBlock, PrepareOpenBlock,
|
||||
@ -95,6 +95,7 @@ use machine::{
|
||||
transaction_ext::Transaction,
|
||||
};
|
||||
use miner::{Miner, MinerService, PendingOrdering};
|
||||
use registrar::RegistrarClient;
|
||||
use snapshot::{self, SnapshotClient, SnapshotWriter};
|
||||
use spec::Spec;
|
||||
use state_db::StateDB;
|
||||
@ -138,8 +139,6 @@ use verification;
|
||||
use verification::queue::kind::BlockLike;
|
||||
use vm::{CreateContractAddress, EnvInfo, LastHashes};
|
||||
|
||||
use_contract!(registry, "res/contracts/registrar.json");
|
||||
|
||||
const MAX_ANCIENT_BLOCKS_QUEUE_SIZE: usize = 4096;
|
||||
// Max number of blocks imported at once.
|
||||
const MAX_ANCIENT_BLOCKS_TO_IMPORT: usize = 4;
|
||||
@ -1415,22 +1414,6 @@ impl TransactionInfo for Client {
|
||||
|
||||
impl BlockChainTrait for Client {}
|
||||
|
||||
impl RegistryInfo for Client {
|
||||
fn registry_address(&self, name: String, block: BlockId) -> Option<Address> {
|
||||
use ethabi::FunctionOutputDecoder;
|
||||
|
||||
let address = self.registrar_address?;
|
||||
|
||||
let (data, decoder) = registry::functions::get_address::call(keccak(name.as_bytes()), "A");
|
||||
let value = decoder.decode(&self.call_contract(block, address, data).ok()?).ok()?;
|
||||
if value.is_zero() {
|
||||
None
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CallContract for Client {
|
||||
fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> {
|
||||
let state_pruned = || CallError::StatePruned.to_string();
|
||||
@ -1445,6 +1428,12 @@ impl CallContract for Client {
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrarClient for Client {
|
||||
fn registrar_address(&self) -> Option<Address> {
|
||||
self.registrar_address
|
||||
}
|
||||
}
|
||||
|
||||
impl ImportBlock for Client {
|
||||
fn import_block(&self, unverified: Unverified) -> EthcoreResult<H256> {
|
||||
if self.chain.read().is_known(&unverified.hash()) {
|
||||
@ -2178,10 +2167,6 @@ impl BlockChainClient for Client {
|
||||
let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
|
||||
self.importer.miner.import_own_transaction(self, signed.into())
|
||||
}
|
||||
|
||||
fn registrar_address(&self) -> Option<Address> {
|
||||
self.registrar_address.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl IoClient for Client {
|
||||
|
@ -23,7 +23,6 @@ extern crate ansi_term;
|
||||
extern crate client_traits;
|
||||
extern crate common_types as types;
|
||||
extern crate engine;
|
||||
extern crate ethabi;
|
||||
extern crate ethcore_blockchain as blockchain;
|
||||
extern crate ethcore_call_contract as call_contract;
|
||||
extern crate ethcore_db as db;
|
||||
@ -45,6 +44,7 @@ extern crate trie_db as trie;
|
||||
extern crate patricia_trie_ethereum as ethtrie;
|
||||
extern crate rand;
|
||||
extern crate rayon;
|
||||
extern crate registrar;
|
||||
extern crate rlp;
|
||||
extern crate rustc_hex;
|
||||
extern crate serde;
|
||||
@ -97,8 +97,6 @@ extern crate serde_json;
|
||||
#[cfg(any(test, feature = "tempdir"))]
|
||||
extern crate tempdir;
|
||||
|
||||
#[macro_use]
|
||||
extern crate ethabi_contract;
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
#[macro_use]
|
||||
|
@ -46,7 +46,8 @@ use types::{
|
||||
};
|
||||
|
||||
use block::SealedBlock;
|
||||
use call_contract::{CallContract, RegistryInfo};
|
||||
use call_contract::CallContract;
|
||||
use registrar::RegistrarClient;
|
||||
use client::{BlockProducer, SealedBlockImporter};
|
||||
use client_traits::{BlockChain, ChainInfo, AccountData, Nonce, ScheduleInfo};
|
||||
use account_state::state::StateInfo;
|
||||
@ -54,7 +55,7 @@ use account_state::state::StateInfo;
|
||||
/// Provides methods to verify incoming external transactions
|
||||
pub trait TransactionVerifierClient: Send + Sync
|
||||
// Required for ServiceTransactionChecker
|
||||
+ CallContract + RegistryInfo
|
||||
+ CallContract + RegistrarClient
|
||||
// Required for verifiying transactions
|
||||
+ BlockChain + ScheduleInfo + AccountData
|
||||
{}
|
||||
|
@ -63,7 +63,8 @@ use types::{
|
||||
use vm::{Schedule, LastHashes};
|
||||
|
||||
use block::{OpenBlock, SealedBlock, ClosedBlock};
|
||||
use call_contract::{CallContract, RegistryInfo};
|
||||
use call_contract::CallContract;
|
||||
use registrar::RegistrarClient;
|
||||
use client::{
|
||||
ReopenBlock, PrepareOpenBlock, ImportSealedBlock, BroadcastProposalBlock, Call,
|
||||
EngineInfo, BlockProducer, SealedBlockImporter,
|
||||
@ -532,7 +533,20 @@ impl BlockInfo for TestBlockChainClient {
|
||||
}
|
||||
|
||||
impl CallContract for TestBlockChainClient {
|
||||
fn call_contract(&self, _id: BlockId, _address: Address, _data: Bytes) -> Result<Bytes, String> { Ok(vec![]) }
|
||||
fn call_contract(
|
||||
&self,
|
||||
_block_id: BlockId,
|
||||
_address: Address,
|
||||
_data: Bytes
|
||||
) -> Result<Bytes, String> {
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrarClient for TestBlockChainClient {
|
||||
fn registrar_address(&self) -> Option<Address> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl TransactionInfo for TestBlockChainClient {
|
||||
@ -543,10 +557,6 @@ impl TransactionInfo for TestBlockChainClient {
|
||||
|
||||
impl BlockChain for TestBlockChainClient {}
|
||||
|
||||
impl RegistryInfo for TestBlockChainClient {
|
||||
fn registry_address(&self, _name: String, _block: BlockId) -> Option<Address> { None }
|
||||
}
|
||||
|
||||
impl ImportBlock for TestBlockChainClient {
|
||||
fn import_block(&self, unverified: Unverified) -> EthcoreResult<H256> {
|
||||
let header = unverified.header;
|
||||
@ -916,8 +926,6 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
let signed = SignedTransaction::new(transaction.with_signature(sig, chain_id)).unwrap();
|
||||
self.miner.import_own_transaction(self, signed.into())
|
||||
}
|
||||
|
||||
fn registrar_address(&self) -> Option<Address> { None }
|
||||
}
|
||||
|
||||
impl IoClient for TestBlockChainClient {
|
||||
|
@ -48,6 +48,7 @@ use test_helpers::{
|
||||
generate_dummy_client_with_data, get_good_dummy_block, get_bad_state_dummy_block
|
||||
};
|
||||
use rustc_hex::ToHex;
|
||||
use registrar::RegistrarClient;
|
||||
|
||||
#[test]
|
||||
fn imports_from_empty() {
|
||||
|
@ -29,6 +29,7 @@ log = "0.4"
|
||||
parity-runtime = { path = "../util/runtime" }
|
||||
parking_lot = "0.9"
|
||||
price-info = { path = "./price-info", optional = true }
|
||||
registrar = { path = "../util/registrar" }
|
||||
rlp = "0.4.0"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
|
@ -33,6 +33,7 @@ extern crate parity_runtime;
|
||||
extern crate parking_lot;
|
||||
#[cfg(feature = "price-info")]
|
||||
extern crate price_info;
|
||||
extern crate registrar;
|
||||
extern crate rlp;
|
||||
extern crate transaction_pool as txpool;
|
||||
extern crate serde;
|
||||
|
@ -19,7 +19,8 @@
|
||||
use std::collections::HashMap;
|
||||
use std::mem;
|
||||
use std::sync::Arc;
|
||||
use call_contract::{RegistryInfo, CallContract};
|
||||
use call_contract::CallContract;
|
||||
use registrar::RegistrarClient;
|
||||
use types::ids::BlockId;
|
||||
use types::transaction::SignedTransaction;
|
||||
use ethabi::FunctionOutputDecoder;
|
||||
@ -37,9 +38,12 @@ pub struct ServiceTransactionChecker {
|
||||
}
|
||||
|
||||
impl ServiceTransactionChecker {
|
||||
|
||||
/// Checks if given address in tx is whitelisted to send service transactions.
|
||||
pub fn check<C: CallContract + RegistryInfo>(&self, client: &C, tx: &SignedTransaction) -> Result<bool, String> {
|
||||
pub fn check<C: CallContract + RegistrarClient>(
|
||||
&self,
|
||||
client: &C,
|
||||
tx: &SignedTransaction
|
||||
) -> Result<bool, String> {
|
||||
let sender = tx.sender();
|
||||
// Skip checking the contract if the transaction does not have zero gas price
|
||||
if !tx.gas_price.is_zero() {
|
||||
@ -50,13 +54,28 @@ impl ServiceTransactionChecker {
|
||||
}
|
||||
|
||||
/// Checks if given address is whitelisted to send service transactions.
|
||||
pub fn check_address<C: CallContract + RegistryInfo>(&self, client: &C, sender: Address) -> Result<bool, String> {
|
||||
pub fn check_address<C>(&self, client: &C, sender: Address) -> Result<bool, String>
|
||||
where C: CallContract + RegistrarClient
|
||||
{
|
||||
trace!(target: "txqueue", "Checking service transaction checker contract from {}", sender);
|
||||
if let Some(allowed) = self.certified_addresses_cache.try_read().as_ref().and_then(|c| c.get(&sender)) {
|
||||
if let Some(allowed) = self
|
||||
.certified_addresses_cache
|
||||
.try_read()
|
||||
.as_ref()
|
||||
.and_then(|c| c.get(&sender))
|
||||
{
|
||||
return Ok(*allowed);
|
||||
}
|
||||
let contract_address = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest)
|
||||
.ok_or_else(|| "contract is not configured")?;
|
||||
|
||||
let contract_address = match client.get_address(
|
||||
SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME,
|
||||
BlockId::Latest
|
||||
) {
|
||||
Ok(Some(addr)) => addr,
|
||||
Ok(None) => return Err("contract is not configured".to_owned()),
|
||||
Err(e) => return Err(e)
|
||||
};
|
||||
|
||||
self.call_contract(client, contract_address, sender).and_then(|allowed| {
|
||||
if let Some(mut cache) = self.certified_addresses_cache.try_write() {
|
||||
cache.insert(sender, allowed);
|
||||
@ -66,13 +85,20 @@ impl ServiceTransactionChecker {
|
||||
}
|
||||
|
||||
/// Refresh certified addresses cache
|
||||
pub fn refresh_cache<C: CallContract + RegistryInfo>(&self, client: &C) -> Result<bool, String> {
|
||||
pub fn refresh_cache<C>(&self, client: &C) -> Result<bool, String>
|
||||
where C: CallContract + RegistrarClient
|
||||
{
|
||||
trace!(target: "txqueue", "Refreshing certified addresses cache");
|
||||
// replace the cache with an empty list,
|
||||
// since it's not recent it won't be used anyway.
|
||||
let cache = mem::replace(&mut *self.certified_addresses_cache.write(), HashMap::default());
|
||||
|
||||
if let Some(contract_address) = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest) {
|
||||
let contract_address_fetch = client.get_address(
|
||||
SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME,
|
||||
BlockId::Latest
|
||||
)?;
|
||||
|
||||
if let Some(contract_address) = contract_address_fetch {
|
||||
let addresses: Vec<_> = cache.keys().collect();
|
||||
let mut cache: HashMap<Address, bool> = HashMap::default();
|
||||
for address in addresses {
|
||||
@ -86,7 +112,14 @@ impl ServiceTransactionChecker {
|
||||
}
|
||||
}
|
||||
|
||||
fn call_contract<C: CallContract + RegistryInfo>(&self, client: &C, contract_address: Address, sender: Address) -> Result<bool, String> {
|
||||
fn call_contract<C>(
|
||||
&self,
|
||||
client: &C,
|
||||
contract_address: Address,
|
||||
sender: Address
|
||||
) -> Result<bool, String>
|
||||
where C: CallContract + RegistrarClient
|
||||
{
|
||||
let (data, decoder) = service_transaction::functions::certified::call(sender);
|
||||
let value = client.call_contract(BlockId::Latest, contract_address, data)?;
|
||||
decoder.decode(&value).map_err(|e| e.to_string())
|
||||
|
@ -46,7 +46,6 @@ extern crate client_traits;
|
||||
extern crate common_types as types;
|
||||
extern crate engine;
|
||||
extern crate ethcore;
|
||||
extern crate ethcore_call_contract as call_contract;
|
||||
extern crate ethcore_db;
|
||||
extern crate ethcore_io as io;
|
||||
extern crate ethcore_light as light;
|
||||
|
@ -20,8 +20,6 @@ use std::time::{Duration, Instant};
|
||||
use std::thread;
|
||||
|
||||
use ansi_term::Colour;
|
||||
use bytes::Bytes;
|
||||
use call_contract::CallContract;
|
||||
use client_traits::{BlockInfo, BlockChainClient};
|
||||
use ethcore::client::{Client, DatabaseCompactionProfile, VMType};
|
||||
use ethcore::miner::{self, stratum, Miner, MinerService, MinerOptions};
|
||||
@ -30,8 +28,7 @@ use spec::SpecParams;
|
||||
use verification::queue::VerifierSettings;
|
||||
use ethcore_logger::{Config as LogConfig, RotatingLogger};
|
||||
use ethcore_service::ClientService;
|
||||
use ethereum_types::Address;
|
||||
use futures::{IntoFuture, Stream};
|
||||
use futures::Stream;
|
||||
use hash_fetch::{self, fetch};
|
||||
use informant::{Informant, LightNodeInformantData, FullNodeInformantData};
|
||||
use journaldb::Algorithm;
|
||||
@ -44,7 +41,6 @@ use sync::{self, SyncConfig, PrivateTxHandler};
|
||||
use types::{
|
||||
client_types::Mode,
|
||||
engines::OptimizeFor,
|
||||
ids::BlockId,
|
||||
snapshot::Snapshotting,
|
||||
};
|
||||
use parity_rpc::{
|
||||
@ -65,12 +61,12 @@ use user_defaults::UserDefaults;
|
||||
use ipfs;
|
||||
use jsonrpc_core;
|
||||
use modules;
|
||||
use registrar::{RegistrarClient, Asynchronous};
|
||||
use rpc;
|
||||
use rpc_apis;
|
||||
use secretstore;
|
||||
use signer;
|
||||
use db;
|
||||
use registrar::RegistrarClient;
|
||||
|
||||
// how often to take periodic snapshots.
|
||||
const SNAPSHOT_PERIOD: u64 = 5000;
|
||||
@ -687,29 +683,18 @@ fn execute_impl<Cr, Rr>(cmd: RunCmd, logger: Arc<RotatingLogger>, on_client_rq:
|
||||
chain_notify.start();
|
||||
}
|
||||
|
||||
let contract_client = {
|
||||
struct FullRegistrar { client: Arc<Client> }
|
||||
impl RegistrarClient for FullRegistrar {
|
||||
type Call = Asynchronous;
|
||||
fn registrar_address(&self) -> Result<Address, String> {
|
||||
self.client.registrar_address()
|
||||
.ok_or_else(|| "Registrar not defined.".into())
|
||||
}
|
||||
fn call_contract(&self, address: Address, data: Bytes) -> Self::Call {
|
||||
Box::new(self.client.call_contract(BlockId::Latest, address, data).into_future())
|
||||
}
|
||||
}
|
||||
|
||||
Arc::new(FullRegistrar { client: client.clone() })
|
||||
};
|
||||
let fetcher = hash_fetch::Client::with_fetch(
|
||||
Arc::downgrade(&(service.client() as Arc<dyn RegistrarClient>)),
|
||||
fetch.clone(),
|
||||
runtime.executor()
|
||||
);
|
||||
|
||||
// the updater service
|
||||
let updater_fetch = fetch.clone();
|
||||
let updater = Updater::new(
|
||||
&Arc::downgrade(&(service.client() as Arc<dyn BlockChainClient>)),
|
||||
&Arc::downgrade(&sync_provider),
|
||||
update_policy,
|
||||
hash_fetch::Client::with_fetch(contract_client.clone(), updater_fetch, runtime.executor())
|
||||
fetcher
|
||||
);
|
||||
service.add_notify(updater.clone());
|
||||
|
||||
|
@ -29,6 +29,7 @@ parity-crypto = "0.4.0"
|
||||
parity-runtime = { path = "../util/runtime" }
|
||||
parking_lot = "0.9"
|
||||
percent-encoding = "2.1.0"
|
||||
registrar = { path = "../util/registrar" }
|
||||
rustc-hex = "1.0"
|
||||
serde = "1.0"
|
||||
serde_derive = "1.0"
|
||||
|
@ -100,7 +100,10 @@ impl CachedContract {
|
||||
}
|
||||
|
||||
pub fn update_contract_address(&mut self) {
|
||||
let contract_address = self.client.read_contract_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.into(), &self.address_source);
|
||||
let contract_address = self.client.read_contract_address(
|
||||
ACL_CHECKER_CONTRACT_REGISTRY_NAME,
|
||||
&self.address_source
|
||||
);
|
||||
if contract_address != self.contract_address {
|
||||
trace!(target: "secretstore", "Configuring for ACL checker contract from address {:?}",
|
||||
contract_address);
|
||||
|
@ -266,7 +266,10 @@ impl CachedContract {
|
||||
|
||||
pub fn update_contract_address(&mut self) {
|
||||
if let Some(ref contract_address_source) = self.contract_address_source {
|
||||
let contract_address = self.client.read_contract_address(KEY_SERVER_SET_CONTRACT_REGISTRY_NAME.into(), contract_address_source);
|
||||
let contract_address = self.client.read_contract_address(
|
||||
KEY_SERVER_SET_CONTRACT_REGISTRY_NAME,
|
||||
contract_address_source
|
||||
);
|
||||
if contract_address != self.contract_address {
|
||||
trace!(target: "secretstore", "{}: Configuring for key server set contract from address {:?}",
|
||||
self.self_key_pair.public(), contract_address);
|
||||
|
@ -31,6 +31,7 @@ extern crate parity_crypto as crypto;
|
||||
extern crate parity_runtime;
|
||||
extern crate parking_lot;
|
||||
extern crate percent_encoding;
|
||||
extern crate registrar;
|
||||
extern crate rustc_hex;
|
||||
extern crate serde;
|
||||
extern crate serde_json;
|
||||
|
@ -222,7 +222,7 @@ impl OnChainServiceContract {
|
||||
|
||||
/// 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 contract_address = self.client.read_contract_address(&self.name, &self.address_source);
|
||||
let mut data = self.data.write();
|
||||
if contract_address != data.contract_address {
|
||||
trace!(target: "secretstore", "{}: installing {} service contract from address {:?}",
|
||||
|
@ -16,7 +16,6 @@
|
||||
|
||||
use std::sync::{Arc, Weak};
|
||||
use bytes::Bytes;
|
||||
use call_contract::RegistryInfo;
|
||||
use common_types::{
|
||||
ids::BlockId,
|
||||
transaction::{Transaction, SignedTransaction, Action},
|
||||
@ -28,6 +27,7 @@ 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.
|
||||
@ -95,12 +95,19 @@ impl TrustedClient {
|
||||
/// 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: String, address: &ContractAddress) -> Option<Address> {
|
||||
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.registry_address(registry_name, BlockId::Hash(block)))
|
||||
.and_then(|block| {
|
||||
client.get_address(registry_name, BlockId::Hash(block))
|
||||
.unwrap_or(None)
|
||||
})
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ version = "1.12.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
call-contract = { package = "ethcore-call-contract", path = "../../ethcore/call-contract" }
|
||||
futures = "0.1"
|
||||
log = "0.4"
|
||||
mime = "0.3"
|
||||
@ -19,6 +20,7 @@ ethereum-types = "0.6.0"
|
||||
parity-runtime = { path = "../../util/runtime" }
|
||||
keccak-hash = "0.2.0"
|
||||
registrar = { path = "../../util/registrar" }
|
||||
types = { path = "../../ethcore/types", package = "common-types" }
|
||||
|
||||
ethabi = "8.0"
|
||||
ethabi-derive = "8.0"
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
use std::{io, fs};
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Weak};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use hash::keccak_buffer;
|
||||
@ -26,7 +26,7 @@ use fetch::{self, Fetch};
|
||||
use futures::{Future, IntoFuture};
|
||||
use parity_runtime::Executor;
|
||||
use urlhint::{URLHintContract, URLHint, URLHintResult};
|
||||
use registrar::{RegistrarClient, Asynchronous};
|
||||
use registrar::RegistrarClient;
|
||||
use ethereum_types::H256;
|
||||
|
||||
/// API for fetching by hash.
|
||||
@ -116,7 +116,7 @@ pub struct Client<F: Fetch + 'static = fetch::Client> {
|
||||
|
||||
impl<F: Fetch + 'static> Client<F> {
|
||||
/// Creates new instance of the `Client` given on-chain contract client, fetch service and task runner.
|
||||
pub fn with_fetch(contract: Arc<dyn RegistrarClient<Call=Asynchronous>>, fetch: F, executor: Executor) -> Self {
|
||||
pub fn with_fetch(contract: Weak<dyn RegistrarClient>, fetch: F, executor: Executor) -> Self {
|
||||
Client {
|
||||
contract: URLHintContract::new(contract),
|
||||
fetch: fetch,
|
||||
@ -133,6 +133,7 @@ impl<F: Fetch + 'static> HashFetch for Client<F> {
|
||||
let random_path = self.random_path.clone();
|
||||
let remote_fetch = self.fetch.clone();
|
||||
let future = self.contract.resolve(hash)
|
||||
.into_future()
|
||||
.map_err(|e| { warn!("Error resolving URL: {}", e); Error::NoResolution })
|
||||
.and_then(|maybe_url| maybe_url.ok_or(Error::NoResolution))
|
||||
.map(|content| match content {
|
||||
@ -197,6 +198,7 @@ mod tests {
|
||||
use urlhint::tests::{FakeRegistrar, URLHINT};
|
||||
use super::{Error, Client, HashFetch, random_temp_path, H256};
|
||||
use std::str::FromStr;
|
||||
use registrar::RegistrarClient;
|
||||
|
||||
fn registrar() -> FakeRegistrar {
|
||||
let mut registrar = FakeRegistrar::new();
|
||||
@ -210,9 +212,9 @@ mod tests {
|
||||
#[test]
|
||||
fn should_return_error_if_hash_not_found() {
|
||||
// given
|
||||
let contract = Arc::new(FakeRegistrar::new());
|
||||
let contract = Arc::new(FakeRegistrar::new()) as Arc<dyn RegistrarClient>;
|
||||
let fetch = FakeFetch::new(None::<usize>);
|
||||
let client = Client::with_fetch(contract.clone(), fetch, Executor::new_sync());
|
||||
let client = Client::with_fetch(Arc::downgrade(&contract), fetch, Executor::new_sync());
|
||||
|
||||
// when
|
||||
let (tx, rx) = mpsc::channel();
|
||||
@ -228,9 +230,9 @@ mod tests {
|
||||
#[test]
|
||||
fn should_return_error_if_response_is_not_successful() {
|
||||
// given
|
||||
let registrar = Arc::new(registrar());
|
||||
let registrar = Arc::new(registrar()) as Arc<dyn RegistrarClient>;
|
||||
let fetch = FakeFetch::new(None::<usize>);
|
||||
let client = Client::with_fetch(registrar.clone(), fetch, Executor::new_sync());
|
||||
let client = Client::with_fetch(Arc::downgrade(®istrar), fetch, Executor::new_sync());
|
||||
|
||||
// when
|
||||
let (tx, rx) = mpsc::channel();
|
||||
@ -246,9 +248,9 @@ mod tests {
|
||||
#[test]
|
||||
fn should_return_hash_mismatch() {
|
||||
// given
|
||||
let registrar = Arc::new(registrar());
|
||||
let registrar = Arc::new(registrar()) as Arc<dyn RegistrarClient>;
|
||||
let fetch = FakeFetch::new(Some(1));
|
||||
let mut client = Client::with_fetch(registrar.clone(), fetch, Executor::new_sync());
|
||||
let mut client = Client::with_fetch(Arc::downgrade(®istrar), fetch, Executor::new_sync());
|
||||
let path = random_temp_path();
|
||||
let path2 = path.clone();
|
||||
client.random_path = Arc::new(move || path2.clone());
|
||||
@ -269,9 +271,9 @@ mod tests {
|
||||
#[test]
|
||||
fn should_return_path_if_hash_matches() {
|
||||
// given
|
||||
let registrar = Arc::new(registrar());
|
||||
let registrar = Arc::new(registrar()) as Arc<dyn RegistrarClient>;
|
||||
let fetch = FakeFetch::new(Some(1));
|
||||
let client = Client::with_fetch(registrar.clone(), fetch, Executor::new_sync());
|
||||
let client = Client::with_fetch(Arc::downgrade(®istrar), fetch, Executor::new_sync());
|
||||
|
||||
// when
|
||||
let (tx, rx) = mpsc::channel();
|
||||
|
@ -21,6 +21,7 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
extern crate call_contract;
|
||||
extern crate ethabi;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate ethereum_types;
|
||||
@ -32,6 +33,7 @@ extern crate parity_runtime;
|
||||
extern crate rand;
|
||||
extern crate rustc_hex;
|
||||
extern crate registrar;
|
||||
extern crate types;
|
||||
|
||||
pub extern crate fetch;
|
||||
|
||||
|
@ -16,15 +16,14 @@
|
||||
|
||||
//! URLHint Contract
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::Weak;
|
||||
use rustc_hex::ToHex;
|
||||
use mime::{self, Mime};
|
||||
use mime_guess;
|
||||
|
||||
use futures::{future, Future};
|
||||
use futures::future::Either;
|
||||
use ethereum_types::{H256, Address};
|
||||
use registrar::{Registrar, RegistrarClient, Asynchronous};
|
||||
use registrar::RegistrarClient;
|
||||
use types::ids::BlockId;
|
||||
|
||||
use_contract!(urlhint, "res/urlhint.json");
|
||||
|
||||
@ -95,20 +94,18 @@ pub enum URLHintResult {
|
||||
/// URLHint Contract interface
|
||||
pub trait URLHint: Send + Sync {
|
||||
/// Resolves given id to registrar entry.
|
||||
fn resolve(&self, id: H256) -> Box<dyn Future<Item = Option<URLHintResult>, Error = String> + Send>;
|
||||
fn resolve(&self, id: H256) -> Result<Option<URLHintResult>, String>;
|
||||
}
|
||||
|
||||
/// `URLHintContract` API
|
||||
pub struct URLHintContract {
|
||||
registrar: Registrar,
|
||||
client: Arc<dyn RegistrarClient<Call=Asynchronous>>,
|
||||
client: Weak<dyn RegistrarClient>,
|
||||
}
|
||||
|
||||
impl URLHintContract {
|
||||
/// Creates new `URLHintContract`
|
||||
pub fn new(client: Arc<dyn RegistrarClient<Call=Asynchronous>>) -> Self {
|
||||
pub fn new(client: Weak<dyn RegistrarClient>) -> Self {
|
||||
URLHintContract {
|
||||
registrar: Registrar::new(client.clone()),
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
@ -123,9 +120,11 @@ fn get_urlhint_content(account_slash_repo: String, owner: Address) -> Content {
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_urlhint_output(output: (String, [u8; 20], Address)) -> Option<URLHintResult> {
|
||||
let (account_slash_repo, commit, owner) = output;
|
||||
|
||||
fn decode_urlhint_output(
|
||||
account_slash_repo: String,
|
||||
commit: [u8; 20],
|
||||
owner: Address
|
||||
) -> Option<URLHintResult> {
|
||||
if owner == Address::zero() {
|
||||
return None;
|
||||
}
|
||||
@ -159,20 +158,26 @@ fn decode_urlhint_output(output: (String, [u8; 20], Address)) -> Option<URLHintR
|
||||
}
|
||||
|
||||
impl URLHint for URLHintContract {
|
||||
fn resolve(&self, id: H256) -> Box<dyn Future<Item = Option<URLHintResult>, Error = String> + Send> {
|
||||
let client = self.client.clone();
|
||||
fn resolve(&self, id: H256) -> Result<Option<URLHintResult>, String> {
|
||||
use urlhint::urlhint::functions::entries::{encode_input, decode_output};
|
||||
|
||||
let future = self.registrar.get_address(GITHUB_HINT)
|
||||
.and_then(move |addr| if !addr.is_zero() {
|
||||
let data = urlhint::functions::entries::encode_input(id);
|
||||
let result = client.call_contract(addr, data)
|
||||
.and_then(move |output| urlhint::functions::entries::decode_output(&output).map_err(|e| e.to_string()))
|
||||
.map(decode_urlhint_output);
|
||||
Either::B(result)
|
||||
} else {
|
||||
Either::A(future::ok(None))
|
||||
});
|
||||
Box::new(future)
|
||||
let client = self.client.clone().upgrade()
|
||||
.ok_or_else(|| "Registrar/contract client unavailable".to_owned())?;
|
||||
|
||||
let returned_address = client.get_address(GITHUB_HINT, BlockId::Latest)?;
|
||||
|
||||
if let Some(address) = returned_address {
|
||||
let data = encode_input(id);
|
||||
let output_bytes = client.call_contract(BlockId::Latest, address, data)?;
|
||||
let (account_slash_repo, commit, owner) = decode_output(&output_bytes)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let url_hint = decode_urlhint_output(account_slash_repo, commit, owner);
|
||||
|
||||
Ok(url_hint)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -205,13 +210,12 @@ pub mod tests {
|
||||
use std::str::FromStr;
|
||||
use rustc_hex::FromHex;
|
||||
|
||||
use futures::{Future, IntoFuture};
|
||||
|
||||
use super::*;
|
||||
use super::guess_mime_type;
|
||||
use parking_lot::Mutex;
|
||||
use ethereum_types::Address;
|
||||
use bytes::{Bytes, ToPretty};
|
||||
use call_contract::CallContract;
|
||||
|
||||
pub struct FakeRegistrar {
|
||||
pub calls: Arc<Mutex<Vec<(String, String)>>>,
|
||||
@ -235,17 +239,23 @@ pub mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrarClient for FakeRegistrar {
|
||||
type Call = Asynchronous;
|
||||
|
||||
fn registrar_address(&self) -> Result<Address, String> {
|
||||
Ok(REGISTRAR.parse().unwrap())
|
||||
}
|
||||
|
||||
fn call_contract(&self, address: Address, data: Bytes) -> Self::Call {
|
||||
impl CallContract for FakeRegistrar {
|
||||
fn call_contract(
|
||||
&self,
|
||||
_block: BlockId,
|
||||
address: Address,
|
||||
data: Bytes
|
||||
) -> Result<Bytes, String> {
|
||||
self.calls.lock().push((address.to_hex(), data.to_hex()));
|
||||
let res = self.responses.lock().remove(0);
|
||||
Box::new(res.into_future())
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
|
||||
impl RegistrarClient for FakeRegistrar {
|
||||
fn registrar_address(&self) -> Option<Address> {
|
||||
Some(REGISTRAR.parse().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
@ -266,10 +276,12 @@ pub mod tests {
|
||||
registrar.responses.lock()[1] = Ok(resolve_result);
|
||||
|
||||
let calls = registrar.calls.clone();
|
||||
let urlhint = URLHintContract::new(Arc::new(registrar));
|
||||
|
||||
let registrar = Arc::new(registrar) as Arc<dyn RegistrarClient>;
|
||||
let urlhint = URLHintContract::new(Arc::downgrade(®istrar));
|
||||
|
||||
// when
|
||||
let res = urlhint.resolve(h256_from_short_str("test")).wait().unwrap();
|
||||
let res = urlhint.resolve(h256_from_short_str("test")).unwrap();
|
||||
let calls = calls.lock();
|
||||
let call0 = calls.get(0).expect("Registrar resolve called");
|
||||
let call1 = calls.get(1).expect("URLHint Resolve called");
|
||||
@ -294,10 +306,12 @@ pub mod tests {
|
||||
Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()),
|
||||
Ok("0000000000000000000000000000000000000000000000000000000000000060ec4c1fe06c808fe3739858c347109b1f5f1ed4b5000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff0000000000000000000000000000000000000000000000000000000000000011657468636f72652f64616f2e636c61696d000000000000000000000000000000".from_hex().unwrap()),
|
||||
]);
|
||||
let urlhint = URLHintContract::new(Arc::new(registrar));
|
||||
|
||||
let registrar = Arc::new(registrar) as Arc<dyn RegistrarClient>;
|
||||
let urlhint = URLHintContract::new(Arc::downgrade(®istrar));
|
||||
|
||||
// when
|
||||
let res = urlhint.resolve(h256_from_short_str("test")).wait().unwrap();
|
||||
let res = urlhint.resolve(h256_from_short_str("test")).unwrap();
|
||||
|
||||
// then
|
||||
assert_eq!(res, Some(URLHintResult::Dapp(GithubApp {
|
||||
@ -316,10 +330,12 @@ pub mod tests {
|
||||
Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()),
|
||||
Ok("00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff000000000000000000000000000000000000000000000000000000000000003c68747470733a2f2f7061726974792e696f2f6173736574732f696d616765732f657468636f72652d626c61636b2d686f72697a6f6e74616c2e706e6700000000".from_hex().unwrap()),
|
||||
]);
|
||||
let urlhint = URLHintContract::new(Arc::new(registrar));
|
||||
|
||||
let registrar = Arc::new(registrar) as Arc<dyn RegistrarClient>;
|
||||
let urlhint = URLHintContract::new(Arc::downgrade(®istrar));
|
||||
|
||||
// when
|
||||
let res = urlhint.resolve(h256_from_short_str("test")).wait().unwrap();
|
||||
let res = urlhint.resolve(h256_from_short_str("test")).unwrap();
|
||||
|
||||
// then
|
||||
assert_eq!(res, Some(URLHintResult::Content(Content {
|
||||
|
@ -251,8 +251,11 @@ impl OperationsClient for OperationsContractClient {
|
||||
}
|
||||
|
||||
let client = self.client.upgrade().ok_or_else(|| "Cannot obtain client")?;
|
||||
let address = client.registry_address("operations".into(), BlockId::Latest).ok_or_else(|| "Cannot get operations contract address")?;
|
||||
let do_call = |data| client.call_contract(BlockId::Latest, address, data).map_err(|e| format!("{:?}", e));
|
||||
let address = client.get_address("operations", BlockId::Latest)?
|
||||
.ok_or_else(|| "Cannot get operations contract address")?;
|
||||
let do_call = |data| {
|
||||
client.call_contract(BlockId::Latest, address, data).map_err(|e| format!("{:?}", e))
|
||||
};
|
||||
|
||||
trace!(target: "updater", "Looking up this_fork for our release: {}/{:?}", CLIENT_ID, this.hash);
|
||||
|
||||
@ -304,7 +307,7 @@ impl OperationsClient for OperationsContractClient {
|
||||
|
||||
fn release_block_number(&self, from: BlockNumber, release: &ReleaseInfo) -> Option<BlockNumber> {
|
||||
let client = self.client.upgrade()?;
|
||||
let address = client.registry_address("operations".into(), BlockId::Latest)?;
|
||||
let address = client.get_address("operations", BlockId::Latest).unwrap_or(None)?;
|
||||
|
||||
let topics = operations::events::release_added::filter(Some(*CLIENT_ID_HASH), Some(release.fork.into()), Some(release.is_critical));
|
||||
let topics = vec![topics.topic0, topics.topic1, topics.topic2, topics.topic3];
|
||||
|
@ -6,8 +6,9 @@ license = "GPL-3.0"
|
||||
authors = ["Parity Technologies <admin@parity.io>"]
|
||||
|
||||
[dependencies]
|
||||
futures = "0.1"
|
||||
call-contract = { package = "ethcore-call-contract", path = "../../ethcore/call-contract" }
|
||||
ethabi = "8.0"
|
||||
ethabi-derive = "8.0"
|
||||
ethabi-contract = "8.0"
|
||||
keccak-hash = "0.2.0"
|
||||
types = { path = "../../ethcore/types", package = "common-types" }
|
||||
|
@ -14,13 +14,14 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
extern crate futures;
|
||||
extern crate call_contract;
|
||||
extern crate ethabi;
|
||||
extern crate ethabi_derive;
|
||||
extern crate keccak_hash;
|
||||
extern crate types;
|
||||
|
||||
#[macro_use]
|
||||
extern crate ethabi_contract;
|
||||
|
||||
mod registrar;
|
||||
pub use registrar::{Registrar, RegistrarClient, Synchronous, Asynchronous};
|
||||
pub use registrar::RegistrarClient;
|
||||
|
@ -14,59 +14,41 @@
|
||||
// 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 futures::{Future, future, IntoFuture};
|
||||
use ethabi::{Address, Bytes};
|
||||
use std::sync::Arc;
|
||||
use call_contract::CallContract;
|
||||
use ethabi::Address;
|
||||
use keccak_hash::keccak;
|
||||
use types::ids::BlockId;
|
||||
|
||||
use_contract!(registrar, "res/registrar.json");
|
||||
|
||||
// Maps a domain name to an Ethereum address
|
||||
const DNS_A_RECORD: &'static str = "A";
|
||||
|
||||
pub type Asynchronous = Box<dyn Future<Item=Bytes, Error=String> + Send>;
|
||||
pub type Synchronous = Result<Bytes, String>;
|
||||
/// Registrar contract interface
|
||||
pub trait RegistrarClient: CallContract + Send + Sync {
|
||||
/// Get address of the registrar itself
|
||||
fn registrar_address(&self) -> Option<Address>;
|
||||
|
||||
/// Registrar is dedicated interface to access the registrar contract
|
||||
/// which in turn generates an address when a client requests one
|
||||
pub struct Registrar {
|
||||
client: Arc<dyn RegistrarClient<Call=Asynchronous>>,
|
||||
}
|
||||
/// Get address from registrar for the specified key.
|
||||
fn get_address(&self, key: &str, block: BlockId) -> Result<Option<Address>, String> {
|
||||
use registrar::registrar::functions::get_address::{encode_input, decode_output};
|
||||
|
||||
impl Registrar {
|
||||
/// Registrar constructor
|
||||
pub fn new(client: Arc<dyn RegistrarClient<Call=Asynchronous>>) -> Self {
|
||||
Self {
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate an address for the given key
|
||||
pub fn get_address<'a>(&self, key: &'a str) -> Box<dyn Future<Item = Address, Error = String> + Send> {
|
||||
// Address of the registrar itself
|
||||
let registrar_address = match self.client.registrar_address() {
|
||||
Ok(a) => a,
|
||||
Err(e) => return Box::new(future::err(e)),
|
||||
let registrar_address = match self.registrar_address() {
|
||||
Some(address) => address,
|
||||
None => return Err("Registrar address not defined.".to_owned())
|
||||
};
|
||||
|
||||
let hashed_key: [u8; 32] = keccak(key).into();
|
||||
let id = registrar::functions::get_address::encode_input(hashed_key, DNS_A_RECORD);
|
||||
let id = encode_input(hashed_key, DNS_A_RECORD);
|
||||
|
||||
let future = self.client.call_contract(registrar_address, id)
|
||||
.and_then(move |address| registrar::functions::get_address::decode_output(&address).map_err(|e| e.to_string()));
|
||||
let address_bytes = self.call_contract(block, registrar_address, id)?;
|
||||
|
||||
Box::new(future)
|
||||
let address = decode_output(&address_bytes).map_err(|e| e.to_string())?;
|
||||
|
||||
if address.is_zero() {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(address))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Registrar contract interface
|
||||
/// Should execute transaction using current blockchain state.
|
||||
pub trait RegistrarClient: Send + Sync {
|
||||
/// Specifies synchronous or asynchronous communication
|
||||
type Call: IntoFuture<Item=Bytes, Error=String>;
|
||||
|
||||
/// Get registrar address
|
||||
fn registrar_address(&self) -> Result<Address, String>;
|
||||
/// Call Contract
|
||||
fn call_contract(&self, address: Address, data: Bytes) -> Self::Call;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user