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:
Toby Dimmick 2019-10-03 14:15:25 +01:00 committed by David
parent 0c0f965354
commit 79a17dedd0
34 changed files with 266 additions and 227 deletions

14
Cargo.lock generated
View File

@ -510,6 +510,7 @@ dependencies = [
"ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "parity-bytes 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"registrar 0.0.1",
"stats 0.1.0", "stats 0.1.0",
"trace 0.1.0", "trace 0.1.0",
"vm 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)", "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"engine 0.1.0", "engine 0.1.0",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
"ethabi 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", "ethash 1.12.0",
"ethcore-accounts 0.1.0", "ethcore-accounts 0.1.0",
"ethcore-blockchain 0.1.0", "ethcore-blockchain 0.1.0",
@ -1052,6 +1050,7 @@ dependencies = [
"pod 0.1.0", "pod 0.1.0",
"rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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)", "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)", "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)", "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)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"price-info 1.12.0", "price-info 1.12.0",
"registrar 0.0.1",
"rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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 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)", "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)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"patricia-trie-ethereum 0.1.0", "patricia-trie-ethereum 0.1.0",
"registrar 0.0.1",
"rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp_derive 0.1.0", "rlp_derive 0.1.0",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1415,6 +1416,7 @@ dependencies = [
"parity-runtime 0.1.0", "parity-runtime 0.1.0",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"registrar 0.0.1",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.99 (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)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2966,7 +2968,6 @@ dependencies = [
"ethcore 1.12.0", "ethcore 1.12.0",
"ethcore-accounts 0.1.0", "ethcore-accounts 0.1.0",
"ethcore-blockchain 0.1.0", "ethcore-blockchain 0.1.0",
"ethcore-call-contract 0.1.0",
"ethcore-db 0.1.0", "ethcore-db 0.1.0",
"ethcore-io 1.12.0", "ethcore-io 1.12.0",
"ethcore-light 1.12.0", "ethcore-light 1.12.0",
@ -3032,9 +3033,11 @@ dependencies = [
name = "parity-hash-fetch" name = "parity-hash-fetch"
version = "1.12.0" version = "1.12.0"
dependencies = [ dependencies = [
"common-types 0.1.0",
"ethabi 8.0.1 (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-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)", "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)", "ethereum-types 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fake-fetch 0.0.1", "fake-fetch 0.0.1",
"fetch 0.1.0", "fetch 0.1.0",
@ -3854,10 +3857,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
name = "registrar" name = "registrar"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"common-types 0.1.0",
"ethabi 8.0.1 (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-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)", "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)", "keccak-hash 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -21,7 +21,6 @@ engine = { path = "ethcore/engine" }
ethcore = { path = "ethcore", features = ["parity"] } ethcore = { path = "ethcore", features = ["parity"] }
ethcore-accounts = { path = "accounts", optional = true } ethcore-accounts = { path = "accounts", optional = true }
ethcore-blockchain = { path = "ethcore/blockchain" } ethcore-blockchain = { path = "ethcore/blockchain" }
ethcore-call-contract = { path = "ethcore/call-contract"}
ethcore-db = { path = "ethcore/db" } ethcore-db = { path = "ethcore/db" }
ethcore-io = { path = "util/io" } ethcore-io = { path = "util/io" }
ethcore-light = { path = "ethcore/light" } ethcore-light = { path = "ethcore/light" }

View File

@ -15,9 +15,6 @@ client-traits = { path = "./client-traits" }
common-types = { path = "types" } common-types = { path = "types" }
engine = { path = "./engine" } engine = { path = "./engine" }
env_logger = { version = "0.5", optional = true } env_logger = { version = "0.5", optional = true }
ethabi = "8.0"
ethabi-contract = "8.0"
ethabi-derive = "8.0"
ethash = { path = "../ethash", optional = true } ethash = { path = "../ethash", optional = true }
ethjson = { path = "../json", optional = true } ethjson = { path = "../json", optional = true }
ethkey = { path = "../accounts/ethkey", 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" } patricia-trie-ethereum = { path = "../util/patricia-trie-ethereum" }
rand = "0.6" rand = "0.6"
rayon = "1.1" rayon = "1.1"
registrar = { path = "../util/registrar" }
rlp = "0.4.0" rlp = "0.4.0"
rustc-hex = "2" rustc-hex = "2"
serde = "1.0" serde = "1.0"

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>. // along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
//! Provides CallContract and RegistryInfo traits //! Provides CallContract trait
use bytes::Bytes; use bytes::Bytes;
use ethereum_types::Address; use ethereum_types::Address;
@ -23,11 +23,10 @@ use types::ids::BlockId;
/// Provides `call_contract` method /// Provides `call_contract` method
pub trait CallContract { pub trait CallContract {
/// Like `call`, but with various defaults. Designed to be used for calling contracts. /// 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>; fn call_contract(
} &self,
block_id: BlockId,
/// Provides information on a blockchain service and it's registry address: Address,
pub trait RegistryInfo { data: Bytes
/// Get the address of a particular blockchain service, if available. ) -> Result<Bytes, String>;
fn registry_address(&self, name: String, block: BlockId) -> Option<Address>;
} }

View File

@ -16,6 +16,7 @@ ethcore-db = { path = "../db" }
ethcore-miner = { path = "../../miner" } ethcore-miner = { path = "../../miner" }
ethereum-types = "0.6.0" ethereum-types = "0.6.0"
kvdb = "0.1" kvdb = "0.1"
registrar = { path = "../../util/registrar" }
stats = { path = "../../util/stats" } stats = { path = "../../util/stats" }
trace = { path = "../trace" } trace = { path = "../trace" }
vm = { path = "../vm" } vm = { path = "../vm" }

View File

@ -22,7 +22,8 @@ use std::{
use account_state::state::StateInfo; use account_state::state::StateInfo;
use blockchain::BlockProvider; use blockchain::BlockProvider;
use bytes::Bytes; use bytes::Bytes;
use call_contract::{CallContract, RegistryInfo}; use call_contract::CallContract;
use registrar::RegistrarClient;
use common_types::{ use common_types::{
basic_account::BasicAccount, basic_account::BasicAccount,
block_status::BlockStatus, block_status::BlockStatus,
@ -218,8 +219,10 @@ pub trait BadBlocks {
/// Blockchain database client. Owns and manages a blockchain and a block queue. /// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContract + RegistryInfo + ImportBlock pub trait BlockChainClient:
+ IoClient + BadBlocks { Sync + Send + AccountData + BlockChain + CallContract + RegistrarClient
+ ImportBlock + IoClient + BadBlocks
{
/// Look up the block number for the given block ID. /// Look up the block number for the given block ID.
fn block_number(&self, id: BlockId) -> Option<BlockNumber>; 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. /// Schedule state-altering transaction to be executed on the next pending block.
fn transact_contract(&self, address: Address, data: Bytes) -> Result<(), transaction::Error>; 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 /// resets the blockchain

View File

@ -36,6 +36,7 @@ parity-crypto = "0.4.0"
parking_lot = "0.9" parking_lot = "0.9"
trie-db = "0.15.0" trie-db = "0.15.0"
patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" } patricia-trie-ethereum = { path = "../../util/patricia-trie-ethereum" }
registrar = { path = "../../util/registrar" }
rlp = "0.4.0" rlp = "0.4.0"
rlp_derive = { path = "../../util/rlp-derive" } rlp_derive = { path = "../../util/rlp-derive" }
rustc-hex = "1.0" rustc-hex = "1.0"

View File

@ -19,7 +19,8 @@
use std::sync::Arc; use std::sync::Arc;
use parking_lot::RwLock; use parking_lot::RwLock;
use ethereum_types::{H256, Address}; use ethereum_types::{H256, Address};
use call_contract::{CallContract, RegistryInfo}; use call_contract::CallContract;
use registrar::RegistrarClient;
use types::ids::BlockId; use types::ids::BlockId;
use ethabi::FunctionOutputDecoder; use ethabi::FunctionOutputDecoder;
@ -53,13 +54,13 @@ pub trait KeyProvider: Send + Sync + 'static {
} }
/// Secret Store keys provider /// 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>, client: Arc<C>,
key_server_account: Option<Address>, key_server_account: Option<Address>,
keys_acl_contract: RwLock<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 /// Create provider
pub fn new(client: Arc<C>, key_server_account: Option<Address>) -> Self { pub fn new(client: Arc<C>, key_server_account: Option<Address>) -> Self {
SecretStoreKeys { 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> { fn key_server_account(&self) -> Option<Address> {
self.key_server_account self.key_server_account
} }
@ -92,7 +95,11 @@ impl<C> KeyProvider for SecretStoreKeys<C> where C: CallContract + RegistryInfo
} }
fn update_acl_contract(&self) { 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 { if *self.keys_acl_contract.read() != contract_address {
trace!(target: "privatetx", "Configuring for ACL checker contract from address {:?}", trace!(target: "privatetx", "Configuring for ACL checker contract from address {:?}",
contract_address); contract_address);
@ -141,6 +148,7 @@ mod tests {
use ethkey::{Secret, KeyPair}; use ethkey::{Secret, KeyPair};
use bytes::Bytes; use bytes::Bytes;
use super::*; use super::*;
use registrar::RegistrarClient;
struct DummyRegistryClient { struct DummyRegistryClient {
registry_address: Option<Address>, registry_address: Option<Address>,
@ -154,12 +162,25 @@ mod tests {
} }
} }
impl RegistryInfo for DummyRegistryClient { impl RegistrarClient for DummyRegistryClient {
fn registry_address(&self, _name: String, _block: BlockId) -> Option<Address> { self.registry_address } 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 { 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] #[test]

View File

@ -51,6 +51,7 @@ extern crate parity_crypto as crypto;
extern crate parking_lot; extern crate parking_lot;
extern crate trie_db as trie; extern crate trie_db as trie;
extern crate patricia_trie_ethereum as ethtrie; extern crate patricia_trie_ethereum as ethtrie;
extern crate registrar;
extern crate rlp; extern crate rlp;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;

View File

@ -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"}
]

View File

@ -51,7 +51,7 @@ use blockchain::{
TransactionAddress, TransactionAddress,
TreeRoute TreeRoute
}; };
use call_contract::{CallContract, RegistryInfo}; use call_contract::CallContract;
use client::{ use client::{
bad_blocks, BlockProducer, BroadcastProposalBlock, Call, bad_blocks, BlockProducer, BroadcastProposalBlock, Call,
ClientConfig, EngineInfo, ImportSealedBlock, PrepareOpenBlock, ClientConfig, EngineInfo, ImportSealedBlock, PrepareOpenBlock,
@ -95,6 +95,7 @@ use machine::{
transaction_ext::Transaction, transaction_ext::Transaction,
}; };
use miner::{Miner, MinerService, PendingOrdering}; use miner::{Miner, MinerService, PendingOrdering};
use registrar::RegistrarClient;
use snapshot::{self, SnapshotClient, SnapshotWriter}; use snapshot::{self, SnapshotClient, SnapshotWriter};
use spec::Spec; use spec::Spec;
use state_db::StateDB; use state_db::StateDB;
@ -138,8 +139,6 @@ use verification;
use verification::queue::kind::BlockLike; use verification::queue::kind::BlockLike;
use vm::{CreateContractAddress, EnvInfo, LastHashes}; use vm::{CreateContractAddress, EnvInfo, LastHashes};
use_contract!(registry, "res/contracts/registrar.json");
const MAX_ANCIENT_BLOCKS_QUEUE_SIZE: usize = 4096; const MAX_ANCIENT_BLOCKS_QUEUE_SIZE: usize = 4096;
// Max number of blocks imported at once. // Max number of blocks imported at once.
const MAX_ANCIENT_BLOCKS_TO_IMPORT: usize = 4; const MAX_ANCIENT_BLOCKS_TO_IMPORT: usize = 4;
@ -1415,22 +1414,6 @@ impl TransactionInfo for Client {
impl BlockChainTrait 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 { impl CallContract for Client {
fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> { fn call_contract(&self, block_id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String> {
let state_pruned = || CallError::StatePruned.to_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 { impl ImportBlock for Client {
fn import_block(&self, unverified: Unverified) -> EthcoreResult<H256> { fn import_block(&self, unverified: Unverified) -> EthcoreResult<H256> {
if self.chain.read().is_known(&unverified.hash()) { 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))?; let signed = SignedTransaction::new(transaction.with_signature(signature, chain_id))?;
self.importer.miner.import_own_transaction(self, signed.into()) self.importer.miner.import_own_transaction(self, signed.into())
} }
fn registrar_address(&self) -> Option<Address> {
self.registrar_address.clone()
}
} }
impl IoClient for Client { impl IoClient for Client {

View File

@ -23,7 +23,6 @@ extern crate ansi_term;
extern crate client_traits; extern crate client_traits;
extern crate common_types as types; extern crate common_types as types;
extern crate engine; extern crate engine;
extern crate ethabi;
extern crate ethcore_blockchain as blockchain; extern crate ethcore_blockchain as blockchain;
extern crate ethcore_call_contract as call_contract; extern crate ethcore_call_contract as call_contract;
extern crate ethcore_db as db; 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 patricia_trie_ethereum as ethtrie;
extern crate rand; extern crate rand;
extern crate rayon; extern crate rayon;
extern crate registrar;
extern crate rlp; extern crate rlp;
extern crate rustc_hex; extern crate rustc_hex;
extern crate serde; extern crate serde;
@ -97,8 +97,6 @@ extern crate serde_json;
#[cfg(any(test, feature = "tempdir"))] #[cfg(any(test, feature = "tempdir"))]
extern crate tempdir; extern crate tempdir;
#[macro_use]
extern crate ethabi_contract;
#[macro_use] #[macro_use]
extern crate log; extern crate log;
#[macro_use] #[macro_use]

View File

@ -46,7 +46,8 @@ use types::{
}; };
use block::SealedBlock; use block::SealedBlock;
use call_contract::{CallContract, RegistryInfo}; use call_contract::CallContract;
use registrar::RegistrarClient;
use client::{BlockProducer, SealedBlockImporter}; use client::{BlockProducer, SealedBlockImporter};
use client_traits::{BlockChain, ChainInfo, AccountData, Nonce, ScheduleInfo}; use client_traits::{BlockChain, ChainInfo, AccountData, Nonce, ScheduleInfo};
use account_state::state::StateInfo; use account_state::state::StateInfo;
@ -54,7 +55,7 @@ use account_state::state::StateInfo;
/// Provides methods to verify incoming external transactions /// Provides methods to verify incoming external transactions
pub trait TransactionVerifierClient: Send + Sync pub trait TransactionVerifierClient: Send + Sync
// Required for ServiceTransactionChecker // Required for ServiceTransactionChecker
+ CallContract + RegistryInfo + CallContract + RegistrarClient
// Required for verifiying transactions // Required for verifiying transactions
+ BlockChain + ScheduleInfo + AccountData + BlockChain + ScheduleInfo + AccountData
{} {}

View File

@ -63,7 +63,8 @@ use types::{
use vm::{Schedule, LastHashes}; use vm::{Schedule, LastHashes};
use block::{OpenBlock, SealedBlock, ClosedBlock}; use block::{OpenBlock, SealedBlock, ClosedBlock};
use call_contract::{CallContract, RegistryInfo}; use call_contract::CallContract;
use registrar::RegistrarClient;
use client::{ use client::{
ReopenBlock, PrepareOpenBlock, ImportSealedBlock, BroadcastProposalBlock, Call, ReopenBlock, PrepareOpenBlock, ImportSealedBlock, BroadcastProposalBlock, Call,
EngineInfo, BlockProducer, SealedBlockImporter, EngineInfo, BlockProducer, SealedBlockImporter,
@ -532,7 +533,20 @@ impl BlockInfo for TestBlockChainClient {
} }
impl CallContract 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 { impl TransactionInfo for TestBlockChainClient {
@ -543,10 +557,6 @@ impl TransactionInfo for TestBlockChainClient {
impl BlockChain 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 { impl ImportBlock for TestBlockChainClient {
fn import_block(&self, unverified: Unverified) -> EthcoreResult<H256> { fn import_block(&self, unverified: Unverified) -> EthcoreResult<H256> {
let header = unverified.header; let header = unverified.header;
@ -916,8 +926,6 @@ impl BlockChainClient for TestBlockChainClient {
let signed = SignedTransaction::new(transaction.with_signature(sig, chain_id)).unwrap(); let signed = SignedTransaction::new(transaction.with_signature(sig, chain_id)).unwrap();
self.miner.import_own_transaction(self, signed.into()) self.miner.import_own_transaction(self, signed.into())
} }
fn registrar_address(&self) -> Option<Address> { None }
} }
impl IoClient for TestBlockChainClient { impl IoClient for TestBlockChainClient {

View File

@ -48,6 +48,7 @@ use test_helpers::{
generate_dummy_client_with_data, get_good_dummy_block, get_bad_state_dummy_block generate_dummy_client_with_data, get_good_dummy_block, get_bad_state_dummy_block
}; };
use rustc_hex::ToHex; use rustc_hex::ToHex;
use registrar::RegistrarClient;
#[test] #[test]
fn imports_from_empty() { fn imports_from_empty() {

View File

@ -29,6 +29,7 @@ log = "0.4"
parity-runtime = { path = "../util/runtime" } parity-runtime = { path = "../util/runtime" }
parking_lot = "0.9" parking_lot = "0.9"
price-info = { path = "./price-info", optional = true } price-info = { path = "./price-info", optional = true }
registrar = { path = "../util/registrar" }
rlp = "0.4.0" rlp = "0.4.0"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"

View File

@ -33,6 +33,7 @@ extern crate parity_runtime;
extern crate parking_lot; extern crate parking_lot;
#[cfg(feature = "price-info")] #[cfg(feature = "price-info")]
extern crate price_info; extern crate price_info;
extern crate registrar;
extern crate rlp; extern crate rlp;
extern crate transaction_pool as txpool; extern crate transaction_pool as txpool;
extern crate serde; extern crate serde;

View File

@ -19,7 +19,8 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::mem; use std::mem;
use std::sync::Arc; use std::sync::Arc;
use call_contract::{RegistryInfo, CallContract}; use call_contract::CallContract;
use registrar::RegistrarClient;
use types::ids::BlockId; use types::ids::BlockId;
use types::transaction::SignedTransaction; use types::transaction::SignedTransaction;
use ethabi::FunctionOutputDecoder; use ethabi::FunctionOutputDecoder;
@ -37,9 +38,12 @@ pub struct ServiceTransactionChecker {
} }
impl ServiceTransactionChecker { impl ServiceTransactionChecker {
/// Checks if given address in tx is whitelisted to send service transactions. /// 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(); let sender = tx.sender();
// Skip checking the contract if the transaction does not have zero gas price // Skip checking the contract if the transaction does not have zero gas price
if !tx.gas_price.is_zero() { if !tx.gas_price.is_zero() {
@ -50,13 +54,28 @@ impl ServiceTransactionChecker {
} }
/// Checks if given address is whitelisted to send service transactions. /// 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); 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); 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| { self.call_contract(client, contract_address, sender).and_then(|allowed| {
if let Some(mut cache) = self.certified_addresses_cache.try_write() { if let Some(mut cache) = self.certified_addresses_cache.try_write() {
cache.insert(sender, allowed); cache.insert(sender, allowed);
@ -66,13 +85,20 @@ impl ServiceTransactionChecker {
} }
/// Refresh certified addresses cache /// 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"); trace!(target: "txqueue", "Refreshing certified addresses cache");
// replace the cache with an empty list, // replace the cache with an empty list,
// since it's not recent it won't be used anyway. // since it's not recent it won't be used anyway.
let cache = mem::replace(&mut *self.certified_addresses_cache.write(), HashMap::default()); 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 addresses: Vec<_> = cache.keys().collect();
let mut cache: HashMap<Address, bool> = HashMap::default(); let mut cache: HashMap<Address, bool> = HashMap::default();
for address in addresses { 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 (data, decoder) = service_transaction::functions::certified::call(sender);
let value = client.call_contract(BlockId::Latest, contract_address, data)?; let value = client.call_contract(BlockId::Latest, contract_address, data)?;
decoder.decode(&value).map_err(|e| e.to_string()) decoder.decode(&value).map_err(|e| e.to_string())

View File

@ -46,7 +46,6 @@ extern crate client_traits;
extern crate common_types as types; extern crate common_types as types;
extern crate engine; extern crate engine;
extern crate ethcore; extern crate ethcore;
extern crate ethcore_call_contract as call_contract;
extern crate ethcore_db; extern crate ethcore_db;
extern crate ethcore_io as io; extern crate ethcore_io as io;
extern crate ethcore_light as light; extern crate ethcore_light as light;

View File

@ -20,8 +20,6 @@ use std::time::{Duration, Instant};
use std::thread; use std::thread;
use ansi_term::Colour; use ansi_term::Colour;
use bytes::Bytes;
use call_contract::CallContract;
use client_traits::{BlockInfo, BlockChainClient}; use client_traits::{BlockInfo, BlockChainClient};
use ethcore::client::{Client, DatabaseCompactionProfile, VMType}; use ethcore::client::{Client, DatabaseCompactionProfile, VMType};
use ethcore::miner::{self, stratum, Miner, MinerService, MinerOptions}; use ethcore::miner::{self, stratum, Miner, MinerService, MinerOptions};
@ -30,8 +28,7 @@ use spec::SpecParams;
use verification::queue::VerifierSettings; use verification::queue::VerifierSettings;
use ethcore_logger::{Config as LogConfig, RotatingLogger}; use ethcore_logger::{Config as LogConfig, RotatingLogger};
use ethcore_service::ClientService; use ethcore_service::ClientService;
use ethereum_types::Address; use futures::Stream;
use futures::{IntoFuture, Stream};
use hash_fetch::{self, fetch}; use hash_fetch::{self, fetch};
use informant::{Informant, LightNodeInformantData, FullNodeInformantData}; use informant::{Informant, LightNodeInformantData, FullNodeInformantData};
use journaldb::Algorithm; use journaldb::Algorithm;
@ -44,7 +41,6 @@ use sync::{self, SyncConfig, PrivateTxHandler};
use types::{ use types::{
client_types::Mode, client_types::Mode,
engines::OptimizeFor, engines::OptimizeFor,
ids::BlockId,
snapshot::Snapshotting, snapshot::Snapshotting,
}; };
use parity_rpc::{ use parity_rpc::{
@ -65,12 +61,12 @@ use user_defaults::UserDefaults;
use ipfs; use ipfs;
use jsonrpc_core; use jsonrpc_core;
use modules; use modules;
use registrar::{RegistrarClient, Asynchronous};
use rpc; use rpc;
use rpc_apis; use rpc_apis;
use secretstore; use secretstore;
use signer; use signer;
use db; use db;
use registrar::RegistrarClient;
// how often to take periodic snapshots. // how often to take periodic snapshots.
const SNAPSHOT_PERIOD: u64 = 5000; 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(); chain_notify.start();
} }
let contract_client = { let fetcher = hash_fetch::Client::with_fetch(
struct FullRegistrar { client: Arc<Client> } Arc::downgrade(&(service.client() as Arc<dyn RegistrarClient>)),
impl RegistrarClient for FullRegistrar { fetch.clone(),
type Call = Asynchronous; runtime.executor()
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() })
};
// the updater service // the updater service
let updater_fetch = fetch.clone();
let updater = Updater::new( let updater = Updater::new(
&Arc::downgrade(&(service.client() as Arc<dyn BlockChainClient>)), &Arc::downgrade(&(service.client() as Arc<dyn BlockChainClient>)),
&Arc::downgrade(&sync_provider), &Arc::downgrade(&sync_provider),
update_policy, update_policy,
hash_fetch::Client::with_fetch(contract_client.clone(), updater_fetch, runtime.executor()) fetcher
); );
service.add_notify(updater.clone()); service.add_notify(updater.clone());

View File

@ -29,6 +29,7 @@ parity-crypto = "0.4.0"
parity-runtime = { path = "../util/runtime" } parity-runtime = { path = "../util/runtime" }
parking_lot = "0.9" parking_lot = "0.9"
percent-encoding = "2.1.0" percent-encoding = "2.1.0"
registrar = { path = "../util/registrar" }
rustc-hex = "1.0" rustc-hex = "1.0"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"

View File

@ -100,7 +100,10 @@ impl CachedContract {
} }
pub fn update_contract_address(&mut self) { 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 { if contract_address != self.contract_address {
trace!(target: "secretstore", "Configuring for ACL checker contract from address {:?}", trace!(target: "secretstore", "Configuring for ACL checker contract from address {:?}",
contract_address); contract_address);

View File

@ -266,7 +266,10 @@ impl CachedContract {
pub fn update_contract_address(&mut self) { pub fn update_contract_address(&mut self) {
if let Some(ref contract_address_source) = self.contract_address_source { 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 { if contract_address != self.contract_address {
trace!(target: "secretstore", "{}: Configuring for key server set contract from address {:?}", trace!(target: "secretstore", "{}: Configuring for key server set contract from address {:?}",
self.self_key_pair.public(), contract_address); self.self_key_pair.public(), contract_address);

View File

@ -31,6 +31,7 @@ extern crate parity_crypto as crypto;
extern crate parity_runtime; extern crate parity_runtime;
extern crate parking_lot; extern crate parking_lot;
extern crate percent_encoding; extern crate percent_encoding;
extern crate registrar;
extern crate rustc_hex; extern crate rustc_hex;
extern crate serde; extern crate serde;
extern crate serde_json; extern crate serde_json;

View File

@ -222,7 +222,7 @@ impl OnChainServiceContract {
/// Update service contract address. /// Update service contract address.
fn update_contract_address(&self) -> bool { 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(); let mut data = self.data.write();
if contract_address != data.contract_address { if contract_address != data.contract_address {
trace!(target: "secretstore", "{}: installing {} service contract from address {:?}", trace!(target: "secretstore", "{}: installing {} service contract from address {:?}",

View File

@ -16,7 +16,6 @@
use std::sync::{Arc, Weak}; use std::sync::{Arc, Weak};
use bytes::Bytes; use bytes::Bytes;
use call_contract::RegistryInfo;
use common_types::{ use common_types::{
ids::BlockId, ids::BlockId,
transaction::{Transaction, SignedTransaction, Action}, transaction::{Transaction, SignedTransaction, Action},
@ -28,6 +27,7 @@ use ethcore::miner::{Miner, MinerService};
use sync::SyncProvider; use sync::SyncProvider;
use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED}; use helpers::{get_confirmed_block_hash, REQUEST_CONFIRMATIONS_REQUIRED};
use {Error, NodeKeyPair, ContractAddress}; use {Error, NodeKeyPair, ContractAddress};
use registrar::RegistrarClient;
#[derive(Clone)] #[derive(Clone)]
/// 'Trusted' client weak reference. /// '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 /// 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 /// trusted. Address from registry is read from registry from block latest block with
/// REQUEST_CONFIRMATIONS_REQUIRED confirmations. /// 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 { match *address {
ContractAddress::Address(ref address) => Some(address.clone()), ContractAddress::Address(ref address) => Some(address.clone()),
ContractAddress::Registry => self.get().and_then(|client| ContractAddress::Registry => self.get().and_then(|client|
get_confirmed_block_hash(&*client, REQUEST_CONFIRMATIONS_REQUIRED) 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)
})
), ),
} }
} }

View File

@ -7,6 +7,7 @@ version = "1.12.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
call-contract = { package = "ethcore-call-contract", path = "../../ethcore/call-contract" }
futures = "0.1" futures = "0.1"
log = "0.4" log = "0.4"
mime = "0.3" mime = "0.3"
@ -19,6 +20,7 @@ ethereum-types = "0.6.0"
parity-runtime = { path = "../../util/runtime" } parity-runtime = { path = "../../util/runtime" }
keccak-hash = "0.2.0" keccak-hash = "0.2.0"
registrar = { path = "../../util/registrar" } registrar = { path = "../../util/registrar" }
types = { path = "../../ethcore/types", package = "common-types" }
ethabi = "8.0" ethabi = "8.0"
ethabi-derive = "8.0" ethabi-derive = "8.0"

View File

@ -18,7 +18,7 @@
use std::{io, fs}; use std::{io, fs};
use std::io::Write; use std::io::Write;
use std::sync::Arc; use std::sync::{Arc, Weak};
use std::path::PathBuf; use std::path::PathBuf;
use hash::keccak_buffer; use hash::keccak_buffer;
@ -26,7 +26,7 @@ use fetch::{self, Fetch};
use futures::{Future, IntoFuture}; use futures::{Future, IntoFuture};
use parity_runtime::Executor; use parity_runtime::Executor;
use urlhint::{URLHintContract, URLHint, URLHintResult}; use urlhint::{URLHintContract, URLHint, URLHintResult};
use registrar::{RegistrarClient, Asynchronous}; use registrar::RegistrarClient;
use ethereum_types::H256; use ethereum_types::H256;
/// API for fetching by hash. /// API for fetching by hash.
@ -116,7 +116,7 @@ pub struct Client<F: Fetch + 'static = fetch::Client> {
impl<F: Fetch + 'static> Client<F> { impl<F: Fetch + 'static> Client<F> {
/// Creates new instance of the `Client` given on-chain contract client, fetch service and task runner. /// 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 { Client {
contract: URLHintContract::new(contract), contract: URLHintContract::new(contract),
fetch: fetch, fetch: fetch,
@ -133,6 +133,7 @@ impl<F: Fetch + 'static> HashFetch for Client<F> {
let random_path = self.random_path.clone(); let random_path = self.random_path.clone();
let remote_fetch = self.fetch.clone(); let remote_fetch = self.fetch.clone();
let future = self.contract.resolve(hash) let future = self.contract.resolve(hash)
.into_future()
.map_err(|e| { warn!("Error resolving URL: {}", e); Error::NoResolution }) .map_err(|e| { warn!("Error resolving URL: {}", e); Error::NoResolution })
.and_then(|maybe_url| maybe_url.ok_or(Error::NoResolution)) .and_then(|maybe_url| maybe_url.ok_or(Error::NoResolution))
.map(|content| match content { .map(|content| match content {
@ -197,6 +198,7 @@ mod tests {
use urlhint::tests::{FakeRegistrar, URLHINT}; use urlhint::tests::{FakeRegistrar, URLHINT};
use super::{Error, Client, HashFetch, random_temp_path, H256}; use super::{Error, Client, HashFetch, random_temp_path, H256};
use std::str::FromStr; use std::str::FromStr;
use registrar::RegistrarClient;
fn registrar() -> FakeRegistrar { fn registrar() -> FakeRegistrar {
let mut registrar = FakeRegistrar::new(); let mut registrar = FakeRegistrar::new();
@ -210,9 +212,9 @@ mod tests {
#[test] #[test]
fn should_return_error_if_hash_not_found() { fn should_return_error_if_hash_not_found() {
// given // given
let contract = Arc::new(FakeRegistrar::new()); let contract = Arc::new(FakeRegistrar::new()) as Arc<dyn RegistrarClient>;
let fetch = FakeFetch::new(None::<usize>); 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 // when
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
@ -228,9 +230,9 @@ mod tests {
#[test] #[test]
fn should_return_error_if_response_is_not_successful() { fn should_return_error_if_response_is_not_successful() {
// given // given
let registrar = Arc::new(registrar()); let registrar = Arc::new(registrar()) as Arc<dyn RegistrarClient>;
let fetch = FakeFetch::new(None::<usize>); let fetch = FakeFetch::new(None::<usize>);
let client = Client::with_fetch(registrar.clone(), fetch, Executor::new_sync()); let client = Client::with_fetch(Arc::downgrade(&registrar), fetch, Executor::new_sync());
// when // when
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
@ -246,9 +248,9 @@ mod tests {
#[test] #[test]
fn should_return_hash_mismatch() { fn should_return_hash_mismatch() {
// given // given
let registrar = Arc::new(registrar()); let registrar = Arc::new(registrar()) as Arc<dyn RegistrarClient>;
let fetch = FakeFetch::new(Some(1)); 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(&registrar), fetch, Executor::new_sync());
let path = random_temp_path(); let path = random_temp_path();
let path2 = path.clone(); let path2 = path.clone();
client.random_path = Arc::new(move || path2.clone()); client.random_path = Arc::new(move || path2.clone());
@ -269,9 +271,9 @@ mod tests {
#[test] #[test]
fn should_return_path_if_hash_matches() { fn should_return_path_if_hash_matches() {
// given // given
let registrar = Arc::new(registrar()); let registrar = Arc::new(registrar()) as Arc<dyn RegistrarClient>;
let fetch = FakeFetch::new(Some(1)); let fetch = FakeFetch::new(Some(1));
let client = Client::with_fetch(registrar.clone(), fetch, Executor::new_sync()); let client = Client::with_fetch(Arc::downgrade(&registrar), fetch, Executor::new_sync());
// when // when
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();

View File

@ -21,6 +21,7 @@
#[macro_use] #[macro_use]
extern crate log; extern crate log;
extern crate call_contract;
extern crate ethabi; extern crate ethabi;
extern crate parity_bytes as bytes; extern crate parity_bytes as bytes;
extern crate ethereum_types; extern crate ethereum_types;
@ -32,6 +33,7 @@ extern crate parity_runtime;
extern crate rand; extern crate rand;
extern crate rustc_hex; extern crate rustc_hex;
extern crate registrar; extern crate registrar;
extern crate types;
pub extern crate fetch; pub extern crate fetch;

View File

@ -16,15 +16,14 @@
//! URLHint Contract //! URLHint Contract
use std::sync::Arc; use std::sync::Weak;
use rustc_hex::ToHex; use rustc_hex::ToHex;
use mime::{self, Mime}; use mime::{self, Mime};
use mime_guess; use mime_guess;
use futures::{future, Future};
use futures::future::Either;
use ethereum_types::{H256, Address}; use ethereum_types::{H256, Address};
use registrar::{Registrar, RegistrarClient, Asynchronous}; use registrar::RegistrarClient;
use types::ids::BlockId;
use_contract!(urlhint, "res/urlhint.json"); use_contract!(urlhint, "res/urlhint.json");
@ -95,20 +94,18 @@ pub enum URLHintResult {
/// URLHint Contract interface /// URLHint Contract interface
pub trait URLHint: Send + Sync { pub trait URLHint: Send + Sync {
/// Resolves given id to registrar entry. /// 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 /// `URLHintContract` API
pub struct URLHintContract { pub struct URLHintContract {
registrar: Registrar, client: Weak<dyn RegistrarClient>,
client: Arc<dyn RegistrarClient<Call=Asynchronous>>,
} }
impl URLHintContract { impl URLHintContract {
/// Creates new `URLHintContract` /// Creates new `URLHintContract`
pub fn new(client: Arc<dyn RegistrarClient<Call=Asynchronous>>) -> Self { pub fn new(client: Weak<dyn RegistrarClient>) -> Self {
URLHintContract { URLHintContract {
registrar: Registrar::new(client.clone()),
client: client, 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> { fn decode_urlhint_output(
let (account_slash_repo, commit, owner) = output; account_slash_repo: String,
commit: [u8; 20],
owner: Address
) -> Option<URLHintResult> {
if owner == Address::zero() { if owner == Address::zero() {
return None; return None;
} }
@ -159,20 +158,26 @@ fn decode_urlhint_output(output: (String, [u8; 20], Address)) -> Option<URLHintR
} }
impl URLHint for URLHintContract { impl URLHint for URLHintContract {
fn resolve(&self, id: H256) -> Box<dyn Future<Item = Option<URLHintResult>, Error = String> + Send> { fn resolve(&self, id: H256) -> Result<Option<URLHintResult>, String> {
let client = self.client.clone(); use urlhint::urlhint::functions::entries::{encode_input, decode_output};
let future = self.registrar.get_address(GITHUB_HINT) let client = self.client.clone().upgrade()
.and_then(move |addr| if !addr.is_zero() { .ok_or_else(|| "Registrar/contract client unavailable".to_owned())?;
let data = urlhint::functions::entries::encode_input(id);
let result = client.call_contract(addr, data) let returned_address = client.get_address(GITHUB_HINT, BlockId::Latest)?;
.and_then(move |output| urlhint::functions::entries::decode_output(&output).map_err(|e| e.to_string()))
.map(decode_urlhint_output); if let Some(address) = returned_address {
Either::B(result) let data = encode_input(id);
} else { let output_bytes = client.call_contract(BlockId::Latest, address, data)?;
Either::A(future::ok(None)) let (account_slash_repo, commit, owner) = decode_output(&output_bytes)
}); .map_err(|e| e.to_string())?;
Box::new(future)
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 std::str::FromStr;
use rustc_hex::FromHex; use rustc_hex::FromHex;
use futures::{Future, IntoFuture};
use super::*; use super::*;
use super::guess_mime_type; use super::guess_mime_type;
use parking_lot::Mutex; use parking_lot::Mutex;
use ethereum_types::Address; use ethereum_types::Address;
use bytes::{Bytes, ToPretty}; use bytes::{Bytes, ToPretty};
use call_contract::CallContract;
pub struct FakeRegistrar { pub struct FakeRegistrar {
pub calls: Arc<Mutex<Vec<(String, String)>>>, pub calls: Arc<Mutex<Vec<(String, String)>>>,
@ -235,17 +239,23 @@ pub mod tests {
} }
} }
impl RegistrarClient for FakeRegistrar { impl CallContract for FakeRegistrar {
type Call = Asynchronous; fn call_contract(
&self,
fn registrar_address(&self) -> Result<Address, String> { _block: BlockId,
Ok(REGISTRAR.parse().unwrap()) address: Address,
} data: Bytes
) -> Result<Bytes, String> {
fn call_contract(&self, address: Address, data: Bytes) -> Self::Call {
self.calls.lock().push((address.to_hex(), data.to_hex())); self.calls.lock().push((address.to_hex(), data.to_hex()));
let res = self.responses.lock().remove(0); 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); registrar.responses.lock()[1] = Ok(resolve_result);
let calls = registrar.calls.clone(); 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(&registrar));
// when // 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 calls = calls.lock();
let call0 = calls.get(0).expect("Registrar resolve called"); let call0 = calls.get(0).expect("Registrar resolve called");
let call1 = calls.get(1).expect("URLHint 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(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()),
Ok("0000000000000000000000000000000000000000000000000000000000000060ec4c1fe06c808fe3739858c347109b1f5f1ed4b5000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff0000000000000000000000000000000000000000000000000000000000000011657468636f72652f64616f2e636c61696d000000000000000000000000000000".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(&registrar));
// when // when
let res = urlhint.resolve(h256_from_short_str("test")).wait().unwrap(); let res = urlhint.resolve(h256_from_short_str("test")).unwrap();
// then // then
assert_eq!(res, Some(URLHintResult::Dapp(GithubApp { assert_eq!(res, Some(URLHintResult::Dapp(GithubApp {
@ -316,10 +330,12 @@ pub mod tests {
Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()), Ok(format!("000000000000000000000000{}", URLHINT).from_hex().unwrap()),
Ok("00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000deadcafebeefbeefcafedeaddeedfeedffffffff000000000000000000000000000000000000000000000000000000000000003c68747470733a2f2f7061726974792e696f2f6173736574732f696d616765732f657468636f72652d626c61636b2d686f72697a6f6e74616c2e706e6700000000".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(&registrar));
// when // when
let res = urlhint.resolve(h256_from_short_str("test")).wait().unwrap(); let res = urlhint.resolve(h256_from_short_str("test")).unwrap();
// then // then
assert_eq!(res, Some(URLHintResult::Content(Content { assert_eq!(res, Some(URLHintResult::Content(Content {

View File

@ -251,8 +251,11 @@ impl OperationsClient for OperationsContractClient {
} }
let client = self.client.upgrade().ok_or_else(|| "Cannot obtain client")?; 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 address = client.get_address("operations", BlockId::Latest)?
let do_call = |data| client.call_contract(BlockId::Latest, address, data).map_err(|e| format!("{:?}", e)); .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); 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> { fn release_block_number(&self, from: BlockNumber, release: &ReleaseInfo) -> Option<BlockNumber> {
let client = self.client.upgrade()?; 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 = 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]; let topics = vec![topics.topic0, topics.topic1, topics.topic2, topics.topic3];

View File

@ -6,8 +6,9 @@ license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
futures = "0.1" call-contract = { package = "ethcore-call-contract", path = "../../ethcore/call-contract" }
ethabi = "8.0" ethabi = "8.0"
ethabi-derive = "8.0" ethabi-derive = "8.0"
ethabi-contract = "8.0" ethabi-contract = "8.0"
keccak-hash = "0.2.0" keccak-hash = "0.2.0"
types = { path = "../../ethcore/types", package = "common-types" }

View File

@ -14,13 +14,14 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>. // along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
extern crate futures; extern crate call_contract;
extern crate ethabi; extern crate ethabi;
extern crate ethabi_derive; extern crate ethabi_derive;
extern crate keccak_hash; extern crate keccak_hash;
extern crate types;
#[macro_use] #[macro_use]
extern crate ethabi_contract; extern crate ethabi_contract;
mod registrar; mod registrar;
pub use registrar::{Registrar, RegistrarClient, Synchronous, Asynchronous}; pub use registrar::RegistrarClient;

View File

@ -14,59 +14,41 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>. // along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use futures::{Future, future, IntoFuture}; use call_contract::CallContract;
use ethabi::{Address, Bytes}; use ethabi::Address;
use std::sync::Arc;
use keccak_hash::keccak; use keccak_hash::keccak;
use types::ids::BlockId;
use_contract!(registrar, "res/registrar.json"); use_contract!(registrar, "res/registrar.json");
// Maps a domain name to an Ethereum address // Maps a domain name to an Ethereum address
const DNS_A_RECORD: &'static str = "A"; const DNS_A_RECORD: &'static str = "A";
pub type Asynchronous = Box<dyn Future<Item=Bytes, Error=String> + Send>; /// Registrar contract interface
pub type Synchronous = Result<Bytes, String>; 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 /// Get address from registrar for the specified key.
/// which in turn generates an address when a client requests one fn get_address(&self, key: &str, block: BlockId) -> Result<Option<Address>, String> {
pub struct Registrar { use registrar::registrar::functions::get_address::{encode_input, decode_output};
client: Arc<dyn RegistrarClient<Call=Asynchronous>>,
}
impl Registrar { let registrar_address = match self.registrar_address() {
/// Registrar constructor Some(address) => address,
pub fn new(client: Arc<dyn RegistrarClient<Call=Asynchronous>>) -> Self { None => return Err("Registrar address not defined.".to_owned())
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 hashed_key: [u8; 32] = keccak(key).into(); 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) let address_bytes = self.call_contract(block, registrar_address, id)?;
.and_then(move |address| registrar::functions::get_address::decode_output(&address).map_err(|e| e.to_string()));
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;
}