diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 2695ad84a..e3c7be66f 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -37,7 +37,7 @@ use client::ancient_import::AncientVerifier; use client::Error as ClientError; use client::{ BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient, - MiningBlockChainClient, EngineClient, TraceFilter, CallAnalytics, BlockImportError, Mode, + MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode, ChainNotify, PruningInfo, ProvingBlockChainClient, }; use encoded; @@ -1852,7 +1852,7 @@ impl MiningBlockChainClient for Client { } } -impl EngineClient for Client { +impl super::traits::EngineClient for Client { fn update_sealing(&self) { self.miner.update_sealing(self) } @@ -1870,6 +1870,22 @@ impl EngineClient for Client { fn epoch_transition_for(&self, parent_hash: H256) -> Option<::engines::EpochTransition> { self.chain.read().epoch_transition_for(parent_hash) } + + fn chain_info(&self) -> BlockChainInfo { + BlockChainClient::chain_info(self) + } + + fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result { + BlockChainClient::call_contract(self, id, address, data) + } + + fn transact_contract(&self, address: Address, data: Bytes) -> Result { + BlockChainClient::transact_contract(self, address, data) + } + + fn block_number(&self, id: BlockId) -> Option { + BlockChainClient::block_number(self, id) + } } impl ProvingBlockChainClient for Client { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 5dfdf5c25..52e89fd0c 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -25,7 +25,7 @@ use devtools::*; use transaction::{Transaction, LocalizedTransaction, PendingTransaction, SignedTransaction, Action}; use blockchain::TreeRoute; use client::{ - BlockChainClient, MiningBlockChainClient, EngineClient, BlockChainInfo, BlockStatus, BlockId, + BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError, ProvingBlockChainClient, }; @@ -780,7 +780,7 @@ impl ProvingBlockChainClient for TestBlockChainClient { } } -impl EngineClient for TestBlockChainClient { +impl super::traits::EngineClient for TestBlockChainClient { fn update_sealing(&self) { self.miner.update_sealing(self) } @@ -796,4 +796,20 @@ impl EngineClient for TestBlockChainClient { fn epoch_transition_for(&self, _block_hash: H256) -> Option<::engines::EpochTransition> { None } + + fn chain_info(&self) -> BlockChainInfo { + BlockChainClient::chain_info(self) + } + + fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result { + BlockChainClient::call_contract(self, id, address, data) + } + + fn transact_contract(&self, address: Address, data: Bytes) -> Result { + BlockChainClient::transact_contract(self, address, data) + } + + fn block_number(&self, id: BlockId) -> Option { + BlockChainClient::block_number(self, id) + } } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index aca369b21..294648e8e 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -307,7 +307,7 @@ pub trait MiningBlockChainClient: BlockChainClient { } /// Client facilities used by internally sealing Engines. -pub trait EngineClient: MiningBlockChainClient { +pub trait EngineClient: Sync + Send { /// Make a new block and seal it. fn update_sealing(&self); @@ -323,6 +323,17 @@ pub trait EngineClient: MiningBlockChainClient { /// /// The block corresponding the the parent hash must be stored already. fn epoch_transition_for(&self, parent_hash: H256) -> Option<::engines::EpochTransition>; + + /// Get block chain info. + fn chain_info(&self) -> BlockChainInfo; + + /// Like `call`, but with various defaults. Designed to be used for calling contracts. + fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result; + + /// Import a transaction: used for misbehaviour reporting. + fn transact_contract(&self, address: Address, data: Bytes) -> Result; + + fn block_number(&self, id: BlockId) -> Option; } /// Extended client interface for providing proofs of the state. diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 0dc33d342..a2e75ee4a 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -23,7 +23,7 @@ use std::time::{UNIX_EPOCH, Duration}; use account_provider::AccountProvider; use block::*; use builtin::Builtin; -use client::{Client, EngineClient}; +use client::EngineClient; use engines::{Call, Engine, Seal, EngineError, ConstructedVerifier}; use error::{Error, TransactionError, BlockError}; use ethjson; @@ -829,9 +829,9 @@ impl Engine for AuthorityRound { Ok(()) } - fn register_client(&self, client: Weak) { + fn register_client(&self, client: Weak) { *self.client.write() = Some(client.clone()); - self.validators.register_contract(client); + self.validators.register_client(client); } fn set_signer(&self, ap: Arc, address: Address, password: String) { diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 68759131d..83a0c0ca3 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -28,7 +28,7 @@ use error::{BlockError, Error}; use evm::Schedule; use ethjson; use header::{Header, BlockNumber}; -use client::Client; +use client::EngineClient; use super::signer::EngineSigner; use super::validator_set::{ValidatorSet, SimpleList, new_validator_set}; @@ -235,8 +235,8 @@ impl Engine for BasicAuthority { } } - fn register_client(&self, client: Weak) { - self.validators.register_contract(client); + fn register_client(&self, client: Weak) { + self.validators.register_client(client); } fn set_signer(&self, ap: Arc, address: Address, password: String) { diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 3997b66c3..0324c2651 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -42,7 +42,7 @@ use self::epoch::PendingTransition; use account_provider::AccountProvider; use block::ExecutedBlock; use builtin::Builtin; -use client::Client; +use client::EngineClient; use evm::env_info::{EnvInfo, LastHashes}; use error::Error; use evm::Schedule; @@ -367,7 +367,7 @@ pub trait Engine : Sync + Send { fn sign(&self, _hash: H256) -> Result { unimplemented!() } /// Add Client which can be used for sealing, querying the state and sending messages. - fn register_client(&self, _client: Weak) {} + fn register_client(&self, _client: Weak) {} /// Trigger next step of the consensus engine. fn step(&self) {} diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 1a9626fff..4e84f130e 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -28,7 +28,7 @@ mod params; use std::sync::Weak; use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering}; use util::*; -use client::{Client, EngineClient}; +use client::EngineClient; use error::{Error, BlockError}; use header::{Header, BlockNumber}; use builtin::Builtin; @@ -766,13 +766,12 @@ impl Engine for Tendermint { self.to_step(next_step); } - fn register_client(&self, client: Weak) { - use client::BlockChainClient; + fn register_client(&self, client: Weak) { if let Some(c) = client.upgrade() { self.height.store(c.chain_info().best_block_number as usize + 1, AtomicOrdering::SeqCst); } *self.client.write() = Some(client.clone()); - self.validators.register_contract(client); + self.validators.register_client(client); } } @@ -1012,7 +1011,7 @@ mod tests { let client = generate_dummy_client(0); let notify = Arc::new(TestNotify::default()); client.add_notify(notify.clone()); - engine.register_client(Arc::downgrade(&client)); + engine.register_client(Arc::downgrade(&client) as _); let prevote_current = vote(engine.as_ref(), |mh| tap.sign(v0, None, mh).map(H520::from), h, r, Step::Prevote, proposal); @@ -1030,7 +1029,6 @@ mod tests { fn seal_submission() { use ethkey::{Generator, Random}; use transaction::{Transaction, Action}; - use client::BlockChainClient; let tap = Arc::new(AccountProvider::transient_provider()); // Accounts for signing votes. @@ -1043,7 +1041,7 @@ mod tests { let notify = Arc::new(TestNotify::default()); client.add_notify(notify.clone()); - engine.register_client(Arc::downgrade(&client)); + engine.register_client(Arc::downgrade(&client) as _); let keypair = Random.generate().unwrap(); let transaction = Transaction { diff --git a/ethcore/src/engines/validator_set/contract.rs b/ethcore/src/engines/validator_set/contract.rs index 46f5c8512..a802db43a 100644 --- a/ethcore/src/engines/validator_set/contract.rs +++ b/ethcore/src/engines/validator_set/contract.rs @@ -23,7 +23,7 @@ use util::*; use futures::Future; use native_contracts::ValidatorReport as Provider; -use client::{Client, BlockChainClient}; +use client::EngineClient; use engines::{Call, Engine}; use header::{Header, BlockNumber}; @@ -34,7 +34,7 @@ use super::safe_contract::ValidatorSafeContract; pub struct ValidatorContract { validators: ValidatorSafeContract, provider: Provider, - client: RwLock>>, // TODO [keorn]: remove + client: RwLock>>, // TODO [keorn]: remove } impl ValidatorContract { @@ -118,8 +118,8 @@ impl ValidatorSet for ValidatorContract { } } - fn register_contract(&self, client: Weak) { - self.validators.register_contract(client.clone()); + fn register_client(&self, client: Weak) { + self.validators.register_client(client.clone()); *self.client.write() = Some(client); } } @@ -143,7 +143,7 @@ mod tests { fn fetches_validators() { let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, None); let vc = Arc::new(ValidatorContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap())); - vc.register_contract(Arc::downgrade(&client)); + vc.register_client(Arc::downgrade(&client) as _); let last_hash = client.best_block_header().hash(); assert!(vc.contains(&last_hash, &Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap())); assert!(vc.contains(&last_hash, &Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap())); @@ -154,7 +154,7 @@ mod tests { let tap = Arc::new(AccountProvider::transient_provider()); let v1 = tap.insert_account("1".sha3().into(), "").unwrap(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_contract, Some(tap.clone())); - client.engine().register_client(Arc::downgrade(&client)); + client.engine().register_client(Arc::downgrade(&client) as _); let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap(); // Make sure reporting can be done. diff --git a/ethcore/src/engines/validator_set/mod.rs b/ethcore/src/engines/validator_set/mod.rs index 56cff365f..06b844ad3 100644 --- a/ethcore/src/engines/validator_set/mod.rs +++ b/ethcore/src/engines/validator_set/mod.rs @@ -27,7 +27,7 @@ use std::sync::Weak; use ids::BlockId; use util::{Bytes, Address, H256}; use ethjson::spec::ValidatorSet as ValidatorSpec; -use client::Client; +use client::EngineClient; use header::{Header, BlockNumber}; #[cfg(test)] @@ -141,5 +141,5 @@ pub trait ValidatorSet: Send + Sync { /// Notifies about benign misbehaviour. fn report_benign(&self, _validator: &Address, _set_block: BlockNumber, _block: BlockNumber) {} /// Allows blockchain state access. - fn register_contract(&self, _client: Weak) {} + fn register_client(&self, _client: Weak) {} } diff --git a/ethcore/src/engines/validator_set/multi.rs b/ethcore/src/engines/validator_set/multi.rs index 5835dbcdb..086f45b98 100644 --- a/ethcore/src/engines/validator_set/multi.rs +++ b/ethcore/src/engines/validator_set/multi.rs @@ -22,7 +22,7 @@ use engines::{Call, Engine}; use util::{Bytes, H256, Address, RwLock}; use ids::BlockId; use header::{BlockNumber, Header}; -use client::{Client, BlockChainClient}; +use client::EngineClient; use super::{SystemCall, ValidatorSet}; type BlockNumberLookup = Box Result + Send + Sync + 'static>; @@ -129,9 +129,9 @@ impl ValidatorSet for Multi { self.correct_set_by_number(set_block).1.report_benign(validator, set_block, block); } - fn register_contract(&self, client: Weak) { + fn register_client(&self, client: Weak) { for set in self.sets.values() { - set.register_contract(client.clone()); + set.register_client(client.clone()); } *self.block_number.write() = Box::new(move |id| client .upgrade() @@ -143,7 +143,7 @@ impl ValidatorSet for Multi { #[cfg(test)] mod tests { use account_provider::AccountProvider; - use client::{BlockChainClient, EngineClient}; + use client::BlockChainClient; use engines::EpochChange; use engines::validator_set::ValidatorSet; use ethkey::Secret; @@ -165,7 +165,7 @@ mod tests { let v0 = tap.insert_account(s0.clone(), "").unwrap(); let v1 = tap.insert_account("1".sha3().into(), "").unwrap(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_multi, Some(tap)); - client.engine().register_client(Arc::downgrade(&client)); + client.engine().register_client(Arc::downgrade(&client) as _); // Make sure txs go through. client.miner().set_gas_floor_target(1_000_000.into()); @@ -173,27 +173,27 @@ mod tests { // Wrong signer for the first block. client.miner().set_engine_signer(v1, "".into()).unwrap(); client.transact_contract(Default::default(), Default::default()).unwrap(); - client.update_sealing(); + ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 0); // Right signer for the first block. client.miner().set_engine_signer(v0, "".into()).unwrap(); - client.update_sealing(); + ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 1); // This time v0 is wrong. client.transact_contract(Default::default(), Default::default()).unwrap(); - client.update_sealing(); + ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 1); client.miner().set_engine_signer(v1, "".into()).unwrap(); - client.update_sealing(); + ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 2); // v1 is still good. client.transact_contract(Default::default(), Default::default()).unwrap(); - client.update_sealing(); + ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 3); // Check syncing. let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_multi, 0, 0, &[]); - sync_client.engine().register_client(Arc::downgrade(&sync_client)); + sync_client.engine().register_client(Arc::downgrade(&sync_client) as _); for i in 1..4 { sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap(); } diff --git a/ethcore/src/engines/validator_set/safe_contract.rs b/ethcore/src/engines/validator_set/safe_contract.rs index f8171a9b9..065c17ef9 100644 --- a/ethcore/src/engines/validator_set/safe_contract.rs +++ b/ethcore/src/engines/validator_set/safe_contract.rs @@ -25,7 +25,7 @@ use util::cache::MemoryLruCache; use rlp::{UntrustedRlp, RlpStream}; use basic_types::LogBloom; -use client::{Client, BlockChainClient}; +use client::EngineClient; use engines::{Call, Engine}; use header::Header; use ids::BlockId; @@ -72,7 +72,7 @@ pub struct ValidatorSafeContract { pub address: Address, validators: RwLock>, provider: Provider, - client: RwLock>>, // TODO [keorn]: remove + client: RwLock>>, // TODO [keorn]: remove } // first proof is just a state proof call of `getValidators` at header's state. @@ -446,7 +446,7 @@ impl ValidatorSet for ValidatorSafeContract { })) } - fn register_contract(&self, client: Weak) { + fn register_client(&self, client: Weak) { trace!(target: "engine", "Setting up contract caller."); *self.client.write() = Some(client); } @@ -460,7 +460,7 @@ mod tests { use spec::Spec; use account_provider::AccountProvider; use transaction::{Transaction, Action}; - use client::{BlockChainClient, EngineClient}; + use client::BlockChainClient; use ethkey::Secret; use miner::MinerService; use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data}; @@ -471,7 +471,7 @@ mod tests { fn fetches_validators() { let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None); let vc = Arc::new(ValidatorSafeContract::new(Address::from_str("0000000000000000000000000000000000000005").unwrap())); - vc.register_contract(Arc::downgrade(&client)); + vc.register_client(Arc::downgrade(&client) as _); let last_hash = client.best_block_header().hash(); assert!(vc.contains(&last_hash, &Address::from_str("7d577a597b2742b498cb5cf0c26cdcd726d39e6e").unwrap())); assert!(vc.contains(&last_hash, &Address::from_str("82a978b3f5962a5b0957d9ee9eef472ee55b42f1").unwrap())); @@ -485,7 +485,7 @@ mod tests { let v1 = tap.insert_account("0".sha3().into(), "").unwrap(); let network_id = Spec::new_validator_safe_contract().network_id(); let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap)); - client.engine().register_client(Arc::downgrade(&client)); + client.engine().register_client(Arc::downgrade(&client) as _); let validator_contract = Address::from_str("0000000000000000000000000000000000000005").unwrap(); client.miner().set_engine_signer(v1, "".into()).unwrap(); @@ -499,7 +499,7 @@ mod tests { data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), }.sign(&s0, Some(network_id)); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); - client.update_sealing(); + ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 1); // Add "1" validator back in. let tx = Transaction { @@ -511,13 +511,13 @@ mod tests { data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(), }.sign(&s0, Some(network_id)); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); - client.update_sealing(); + ::client::EngineClient::update_sealing(&*client); // The transaction is not yet included so still unable to seal. assert_eq!(client.chain_info().best_block_number, 1); // Switch to the validator that is still there. client.miner().set_engine_signer(v0, "".into()).unwrap(); - client.update_sealing(); + ::client::EngineClient::update_sealing(&*client); assert_eq!(client.chain_info().best_block_number, 2); // Switch back to the added validator, since the state is updated. client.miner().set_engine_signer(v1, "".into()).unwrap(); @@ -530,13 +530,13 @@ mod tests { data: Vec::new(), }.sign(&s0, Some(network_id)); client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap(); - client.update_sealing(); + ::client::EngineClient::update_sealing(&*client); // Able to seal again. assert_eq!(client.chain_info().best_block_number, 3); // Check syncing. let sync_client = generate_dummy_client_with_spec_and_data(Spec::new_validator_safe_contract, 0, 0, &[]); - sync_client.engine().register_client(Arc::downgrade(&sync_client)); + sync_client.engine().register_client(Arc::downgrade(&sync_client) as _); for i in 1..4 { sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap(); } diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index e4c3d7519..5bc15d9bb 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -112,7 +112,7 @@ impl ClientService { }); io_service.register_handler(client_io)?; - spec.engine.register_client(Arc::downgrade(&client)); + spec.engine.register_client(Arc::downgrade(&client) as _); let stop_guard = ::devtools::StopGuard::new(); run_ipc(ipc_path, client.clone(), snapshot.clone(), stop_guard.share()); diff --git a/ethcore/src/snapshot/tests/proof_of_authority.rs b/ethcore/src/snapshot/tests/proof_of_authority.rs index a62dbaf10..1d4841a96 100644 --- a/ethcore/src/snapshot/tests/proof_of_authority.rs +++ b/ethcore/src/snapshot/tests/proof_of_authority.rs @@ -93,7 +93,7 @@ fn make_chain(accounts: Arc, blocks_beyond: usize, transitions: let mut cur_signers = vec![*RICH_ADDR]; { let engine = client.engine(); - engine.register_client(Arc::downgrade(&client)); + engine.register_client(Arc::downgrade(&client) as _); } {