Merge branch 'master' into util_error_chain

This commit is contained in:
debris
2017-09-05 14:58:35 +02:00
92 changed files with 2464 additions and 2652 deletions

View File

@@ -25,7 +25,7 @@ use std::cmp;
use account_provider::AccountProvider;
use block::*;
use builtin::Builtin;
use client::EngineClient;
use client::{Client, EngineClient};
use engines::{Call, Engine, Seal, EngineError, ConstructedVerifier};
use error::{Error, TransactionError, BlockError};
use ethjson;
@@ -647,8 +647,6 @@ impl Engine for AuthorityRound {
(&active_set as &_, epoch_manager.epoch_transition_number)
};
// always report with "self.validators" so that the report actually gets
// to the contract.
let report = |report| match report {
Report::Benign(address, block_number) =>
self.validators.report_benign(&address, set_number, block_number),
@@ -741,18 +739,13 @@ impl Engine for AuthorityRound {
{
if let Ok(finalized) = epoch_manager.finality_checker.push_hash(chain_head.hash(), *chain_head.author()) {
let mut finalized = finalized.into_iter();
while let Some(finalized_hash) = finalized.next() {
if let Some(pending) = transition_store(finalized_hash) {
let finality_proof = ::std::iter::once(finalized_hash)
while let Some(hash) = finalized.next() {
if let Some(pending) = transition_store(hash) {
let finality_proof = ::std::iter::once(hash)
.chain(finalized)
.chain(epoch_manager.finality_checker.unfinalized_hashes())
.map(|h| if h == chain_head.hash() {
// chain closure only stores ancestry, but the chain head is also
// unfinalized.
chain_head.clone()
} else {
chain(h).expect("these headers fetched before when constructing finality checker; qed")
})
.map(|hash| chain(hash)
.expect("these headers fetched before when constructing finality checker; qed"))
.collect::<Vec<Header>>();
// this gives us the block number for `hash`, assuming it's ancestry.
@@ -816,9 +809,9 @@ impl Engine for AuthorityRound {
Ok(())
}
fn register_client(&self, client: Weak<EngineClient>) {
fn register_client(&self, client: Weak<Client>) {
*self.client.write() = Some(client.clone());
self.validators.register_client(client);
self.validators.register_contract(client);
}
fn set_signer(&self, ap: Arc<AccountProvider>, address: Address, password: String) {

View File

@@ -34,7 +34,7 @@ use error::{BlockError, Error};
use evm::Schedule;
use ethjson;
use header::{Header, BlockNumber};
use client::EngineClient;
use client::Client;
use semantic_version::SemanticVersion;
use super::signer::EngineSigner;
use super::validator_set::{ValidatorSet, SimpleList, new_validator_set};
@@ -237,8 +237,8 @@ impl Engine for BasicAuthority {
}
}
fn register_client(&self, client: Weak<EngineClient>) {
self.validators.register_client(client);
fn register_client(&self, client: Weak<Client>) {
self.validators.register_contract(client);
}
fn set_signer(&self, ap: Arc<AccountProvider>, address: Address, password: String) {

View File

@@ -44,7 +44,7 @@ use self::epoch::PendingTransition;
use account_provider::AccountProvider;
use block::ExecutedBlock;
use builtin::Builtin;
use client::EngineClient;
use client::Client;
use vm::{EnvInfo, LastHashes, Schedule, CreateContractAddress};
use error::Error;
use header::{Header, BlockNumber};
@@ -124,22 +124,12 @@ pub type Headers<'a> = Fn(H256) -> Option<Header> + 'a;
/// Type alias for a function we can query pending transitions by block hash through.
pub type PendingTransitionStore<'a> = Fn(H256) -> Option<PendingTransition> + 'a;
/// Proof dependent on state.
pub trait StateDependentProof: Send + Sync {
/// Generate a proof, given the state.
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String>;
/// Check a proof generated elsewhere (potentially by a peer).
// `engine` needed to check state proofs, while really this should
// just be state machine params.
fn check_proof(&self, engine: &Engine, proof: &[u8]) -> Result<(), String>;
}
/// Proof generated on epoch change.
pub enum Proof {
/// Known proof (extracted from signal)
/// Known proof (exctracted from signal)
Known(Vec<u8>),
/// State dependent proof.
WithState(Arc<StateDependentProof>),
/// Extract proof from caller.
WithState(Box<Fn(&Call) -> Result<Vec<u8>, String>>),
}
/// Generated epoch verifier.
@@ -371,7 +361,7 @@ pub trait Engine : Sync + Send {
fn sign(&self, _hash: H256) -> Result<Signature, Error> { unimplemented!() }
/// Add Client which can be used for sealing, querying the state and sending messages.
fn register_client(&self, _client: Weak<EngineClient>) {}
fn register_client(&self, _client: Weak<Client>) {}
/// Trigger next step of the consensus engine.
fn step(&self) {}

View File

@@ -35,7 +35,7 @@ use bigint::hash::{H256, H520};
use parking_lot::RwLock;
use util::*;
use unexpected::{OutOfBounds, Mismatch};
use client::EngineClient;
use client::{Client, EngineClient};
use error::{Error, BlockError};
use header::{Header, BlockNumber};
use builtin::Builtin;
@@ -571,35 +571,18 @@ impl Engine for Tendermint {
Ok(())
}
/// Verify gas limit.
/// Verify validators and gas limit.
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
if header.number() == 0 {
return Err(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() }).into());
}
let gas_limit_divisor = self.params().gas_limit_bound_divisor;
let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
self.validators.report_malicious(header.author(), header.number(), header.number(), Default::default());
return Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }).into());
}
Ok(())
}
fn verify_block_external(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
if let Ok(proposal) = ConsensusMessage::new_proposal(header) {
let proposer = proposal.verify()?;
if !self.is_authority(&proposer) {
return Err(EngineError::NotAuthorized(proposer).into());
}
self.check_view_proposer(
header.parent_hash(),
proposal.vote_step.height,
proposal.vote_step.view,
&proposer
).map_err(Into::into)
self.check_view_proposer(header.parent_hash(), proposal.vote_step.height, proposal.vote_step.view, &proposer)?;
} else {
let vote_step = VoteStep::new(header.number() as usize, consensus_view(header)?, Step::Precommit);
let precommit_hash = message_hash(vote_step.clone(), header.bare_hash());
@@ -625,8 +608,18 @@ impl Engine for Tendermint {
}
}
self.check_above_threshold(origins.len()).map_err(Into::into)
self.check_above_threshold(origins.len())?
}
let gas_limit_divisor = self.params().gas_limit_bound_divisor;
let min_gas = parent.gas_limit().clone() - parent.gas_limit().clone() / gas_limit_divisor;
let max_gas = parent.gas_limit().clone() + parent.gas_limit().clone() / gas_limit_divisor;
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
self.validators.report_malicious(header.author(), header.number(), header.number(), Default::default());
return Err(BlockError::InvalidGasLimit(OutOfBounds { min: Some(min_gas), max: Some(max_gas), found: header.gas_limit().clone() }).into());
}
Ok(())
}
fn signals_epoch_end(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
@@ -761,12 +754,13 @@ impl Engine for Tendermint {
self.to_step(next_step);
}
fn register_client(&self, client: Weak<EngineClient>) {
fn register_client(&self, client: Weak<Client>) {
use client::BlockChainClient;
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_client(client);
self.validators.register_contract(client);
}
}
@@ -894,14 +888,14 @@ mod tests {
let seal = proposal_seal(&tap, &header, 0);
header.set_seal(seal);
// Good proposer.
assert!(engine.verify_block_external(&header, None).is_ok());
assert!(engine.verify_block_family(&header, &parent_header, None).is_ok());
let validator = insert_and_unlock(&tap, "0");
header.set_author(validator);
let seal = proposal_seal(&tap, &header, 0);
header.set_seal(seal);
// Bad proposer.
match engine.verify_block_external(&header, None) {
match engine.verify_block_family(&header, &parent_header, None) {
Err(Error::Engine(EngineError::NotProposer(_))) => {},
_ => panic!(),
}
@@ -911,7 +905,7 @@ mod tests {
let seal = proposal_seal(&tap, &header, 0);
header.set_seal(seal);
// Not authority.
match engine.verify_block_external(&header, None) {
match engine.verify_block_family(&header, &parent_header, None) {
Err(Error::Engine(EngineError::NotAuthorized(_))) => {},
_ => panic!(),
};
@@ -941,7 +935,7 @@ mod tests {
header.set_seal(seal.clone());
// One good signature is not enough.
match engine.verify_block_external(&header, None) {
match engine.verify_block_family(&header, &parent_header, None) {
Err(Error::Engine(EngineError::BadSealFieldSize(_))) => {},
_ => panic!(),
}
@@ -952,7 +946,7 @@ mod tests {
seal[2] = ::rlp::encode_list(&vec![H520::from(signature1.clone()), H520::from(signature0.clone())]).into_vec();
header.set_seal(seal.clone());
assert!(engine.verify_block_external(&header, None).is_ok());
assert!(engine.verify_block_family(&header, &parent_header, None).is_ok());
let bad_voter = insert_and_unlock(&tap, "101");
let bad_signature = tap.sign(bad_voter, None, keccak(vote_info)).unwrap();
@@ -961,7 +955,7 @@ mod tests {
header.set_seal(seal);
// One good and one bad signature.
match engine.verify_block_external(&header, None) {
match engine.verify_block_family(&header, &parent_header, None) {
Err(Error::Engine(EngineError::NotAuthorized(_))) => {},
_ => panic!(),
};
@@ -1007,7 +1001,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) as _);
engine.register_client(Arc::downgrade(&client));
let prevote_current = vote(engine.as_ref(), |mh| tap.sign(v0, None, mh).map(H520::from), h, r, Step::Prevote, proposal);
@@ -1025,6 +1019,7 @@ 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.
@@ -1037,7 +1032,7 @@ mod tests {
let notify = Arc::new(TestNotify::default());
client.add_notify(notify.clone());
engine.register_client(Arc::downgrade(&client) as _);
engine.register_client(Arc::downgrade(&client));
let keypair = Random.generate().unwrap();
let transaction = Transaction {

View File

@@ -25,7 +25,7 @@ use util::*;
use futures::Future;
use native_contracts::ValidatorReport as Provider;
use client::EngineClient;
use client::{Client, BlockChainClient};
use engines::{Call, Engine};
use header::{Header, BlockNumber};
@@ -36,7 +36,7 @@ use super::safe_contract::ValidatorSafeContract;
pub struct ValidatorContract {
validators: ValidatorSafeContract,
provider: Provider,
client: RwLock<Option<Weak<EngineClient>>>, // TODO [keorn]: remove
client: RwLock<Option<Weak<Client>>>, // TODO [keorn]: remove
}
impl ValidatorContract {
@@ -120,8 +120,8 @@ impl ValidatorSet for ValidatorContract {
}
}
fn register_client(&self, client: Weak<EngineClient>) {
self.validators.register_client(client.clone());
fn register_contract(&self, client: Weak<Client>) {
self.validators.register_contract(client.clone());
*self.client.write() = Some(client);
}
}
@@ -148,7 +148,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("0000000000000000000000000000000000000005".parse::<Address>().unwrap()));
vc.register_client(Arc::downgrade(&client) as _);
vc.register_contract(Arc::downgrade(&client));
let last_hash = client.best_block_header().hash();
assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::<Address>().unwrap()));
assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::<Address>().unwrap()));
@@ -159,7 +159,7 @@ mod tests {
let tap = Arc::new(AccountProvider::transient_provider());
let v1 = tap.insert_account(keccak("1").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) as _);
client.engine().register_client(Arc::downgrade(&client));
let validator_contract = "0000000000000000000000000000000000000005".parse::<Address>().unwrap();
// Make sure reporting can be done.

View File

@@ -28,7 +28,7 @@ use ids::BlockId;
use bigint::hash::H256;
use util::{Bytes, Address};
use ethjson::spec::ValidatorSet as ValidatorSpec;
use client::EngineClient;
use client::Client;
use header::{Header, BlockNumber};
#[cfg(test)]
@@ -142,5 +142,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_client(&self, _client: Weak<EngineClient>) {}
fn register_contract(&self, _client: Weak<Client>) {}
}

View File

@@ -24,7 +24,7 @@ use parking_lot::RwLock;
use util::{Bytes, Address};
use ids::BlockId;
use header::{BlockNumber, Header};
use client::EngineClient;
use client::{Client, BlockChainClient};
use super::{SystemCall, ValidatorSet};
type BlockNumberLookup = Box<Fn(BlockId) -> Result<BlockNumber, String> + Send + Sync + 'static>;
@@ -131,9 +131,9 @@ impl ValidatorSet for Multi {
self.correct_set_by_number(set_block).1.report_benign(validator, set_block, block);
}
fn register_client(&self, client: Weak<EngineClient>) {
fn register_contract(&self, client: Weak<Client>) {
for set in self.sets.values() {
set.register_client(client.clone());
set.register_contract(client.clone());
}
*self.block_number.write() = Box::new(move |id| client
.upgrade()
@@ -148,7 +148,7 @@ mod tests {
use std::collections::BTreeMap;
use hash::keccak;
use account_provider::AccountProvider;
use client::BlockChainClient;
use client::{BlockChainClient, EngineClient};
use engines::EpochChange;
use engines::validator_set::ValidatorSet;
use ethkey::Secret;
@@ -170,7 +170,7 @@ mod tests {
let v0 = tap.insert_account(s0.clone(), "").unwrap();
let v1 = tap.insert_account(keccak("1").into(), "").unwrap();
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_multi, Some(tap));
client.engine().register_client(Arc::downgrade(&client) as _);
client.engine().register_client(Arc::downgrade(&client));
// Make sure txs go through.
client.miner().set_gas_floor_target(1_000_000.into());
@@ -178,27 +178,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::EngineClient::update_sealing(&*client);
client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 0);
// Right signer for the first block.
client.miner().set_engine_signer(v0, "".into()).unwrap();
::client::EngineClient::update_sealing(&*client);
client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 1);
// This time v0 is wrong.
client.transact_contract(Default::default(), Default::default()).unwrap();
::client::EngineClient::update_sealing(&*client);
client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 1);
client.miner().set_engine_signer(v1, "".into()).unwrap();
::client::EngineClient::update_sealing(&*client);
client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 2);
// v1 is still good.
client.transact_contract(Default::default(), Default::default()).unwrap();
::client::EngineClient::update_sealing(&*client);
client.update_sealing();
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) as _);
sync_client.engine().register_client(Arc::downgrade(&sync_client));
for i in 1..4 {
sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap();
}

View File

@@ -23,15 +23,14 @@ use hash::keccak;
use bigint::prelude::U256;
use bigint::hash::{H160, H256};
use parking_lot::{Mutex, RwLock};
use parking_lot::RwLock;
use util::*;
use util::cache::MemoryLruCache;
use unexpected::Mismatch;
use rlp::{UntrustedRlp, RlpStream};
use basic_types::LogBloom;
use client::EngineClient;
use client::{Client, BlockChainClient};
use engines::{Call, Engine};
use header::Header;
use ids::BlockId;
@@ -50,35 +49,12 @@ lazy_static! {
static ref EVENT_NAME_HASH: H256 = keccak(EVENT_NAME);
}
// state-dependent proofs for the safe contract:
// only "first" proofs are such.
struct StateProof {
header: Mutex<Header>,
provider: Provider,
}
impl ::engines::StateDependentProof for StateProof {
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String> {
prove_initial(&self.provider, &*self.header.lock(), caller)
}
fn check_proof(&self, engine: &Engine, proof: &[u8]) -> Result<(), String> {
let (header, state_items) = decode_first_proof(&UntrustedRlp::new(proof))
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
if &header != &*self.header.lock(){
return Err("wrong header in proof".into());
}
check_first_proof(engine, &self.provider, header, &state_items).map(|_| ())
}
}
/// The validator contract should have the following interface:
pub struct ValidatorSafeContract {
pub address: Address,
validators: RwLock<MemoryLruCache<H256, SimpleList>>,
provider: Provider,
client: RwLock<Option<Weak<EngineClient>>>, // TODO [keorn]: remove
client: RwLock<Option<Weak<Client>>>, // TODO [keorn]: remove
}
// first proof is just a state proof call of `getValidators` at header's state.
@@ -92,59 +68,6 @@ fn encode_first_proof(header: &Header, state_items: &[Vec<u8>]) -> Bytes {
stream.out()
}
// check a first proof: fetch the validator set at the given block.
fn check_first_proof(engine: &Engine, provider: &Provider, old_header: Header, state_items: &[DBValue])
-> Result<Vec<Address>, String>
{
use transaction::{Action, Transaction};
// TODO: match client contract_call_tx more cleanly without duplication.
const PROVIDED_GAS: u64 = 50_000_000;
let env_info = ::vm::EnvInfo {
number: old_header.number(),
author: *old_header.author(),
difficulty: *old_header.difficulty(),
gas_limit: PROVIDED_GAS.into(),
timestamp: old_header.timestamp(),
last_hashes: {
// this will break if we don't inclue all 256 last hashes.
let mut last_hashes: Vec<_> = (0..256).map(|_| H256::default()).collect();
last_hashes[255] = *old_header.parent_hash();
Arc::new(last_hashes)
},
gas_used: 0.into(),
};
// check state proof using given engine.
let number = old_header.number();
provider.get_validators(move |a, d| {
let from = Address::default();
let tx = Transaction {
nonce: engine.account_start_nonce(number),
action: Action::Call(a),
gas: PROVIDED_GAS.into(),
gas_price: U256::default(),
value: U256::default(),
data: d,
}.fake_sign(from);
let res = ::state::check_proof(
state_items,
*old_header.state_root(),
&tx,
engine,
&env_info,
);
match res {
::state::ProvedExecution::BadProof => Err("Bad proof".into()),
::state::ProvedExecution::Failed(e) => Err(format!("Failed call: {}", e)),
::state::ProvedExecution::Complete(e) => Ok(e.output),
}
}).wait()
}
fn decode_first_proof(rlp: &UntrustedRlp) -> Result<(Header, Vec<DBValue>), ::error::Error> {
let header = rlp.val_at(0)?;
let state_items = rlp.at(1)?.iter().map(|x| {
@@ -182,7 +105,8 @@ fn prove_initial(provider: &Provider, header: &Header, caller: &Call) -> Result<
Ok(result)
};
provider.get_validators(caller).wait()
provider.get_validators(caller)
.wait()
};
res.map(|validators| {
@@ -336,11 +260,9 @@ impl ValidatorSet for ValidatorSafeContract {
// transition to the first block of a contract requires finality but has no log event.
if first {
debug!(target: "engine", "signalling transition to fresh contract.");
let state_proof = Arc::new(StateProof {
header: Mutex::new(header.clone()),
provider: self.provider.clone(),
});
return ::engines::EpochChange::Yes(::engines::Proof::WithState(state_proof as Arc<_>));
let (provider, header) = (self.provider.clone(), header.clone());
let with_caller: Box<Fn(&Call) -> _> = Box::new(move |caller| prove_initial(&provider, &header, caller));
return ::engines::EpochChange::Yes(::engines::Proof::WithState(with_caller))
}
// otherwise, we're checking for logs.
@@ -369,16 +291,61 @@ impl ValidatorSet for ValidatorSafeContract {
fn epoch_set(&self, first: bool, engine: &Engine, _number: ::header::BlockNumber, proof: &[u8])
-> Result<(SimpleList, Option<H256>), ::error::Error>
{
use transaction::{Action, Transaction};
let rlp = UntrustedRlp::new(proof);
if first {
trace!(target: "engine", "Recovering initial epoch set");
// TODO: match client contract_call_tx more cleanly without duplication.
const PROVIDED_GAS: u64 = 50_000_000;
let (old_header, state_items) = decode_first_proof(&rlp)?;
let number = old_header.number();
let old_hash = old_header.hash();
let addresses = check_first_proof(engine, &self.provider, old_header, &state_items)
.map_err(::engines::EngineError::InsufficientProof)?;
let env_info = ::vm::EnvInfo {
number: old_header.number(),
author: *old_header.author(),
difficulty: *old_header.difficulty(),
gas_limit: PROVIDED_GAS.into(),
timestamp: old_header.timestamp(),
last_hashes: {
// this will break if we don't inclue all 256 last hashes.
let mut last_hashes: Vec<_> = (0..256).map(|_| H256::default()).collect();
last_hashes[255] = *old_header.parent_hash();
Arc::new(last_hashes)
},
gas_used: 0.into(),
};
// check state proof using given engine.
let number = old_header.number();
let addresses = self.provider.get_validators(move |a, d| {
let from = Address::default();
let tx = Transaction {
nonce: engine.account_start_nonce(number),
action: Action::Call(a),
gas: PROVIDED_GAS.into(),
gas_price: U256::default(),
value: U256::default(),
data: d,
}.fake_sign(from);
let res = ::state::check_proof(
&state_items,
*old_header.state_root(),
&tx,
engine,
&env_info,
);
match res {
::state::ProvedExecution::BadProof => Err("Bad proof".into()),
::state::ProvedExecution::Failed(e) => Err(format!("Failed call: {}", e)),
::state::ProvedExecution::Complete(e) => Ok(e.output),
}
}).wait().map_err(::engines::EngineError::InsufficientProof)?;
trace!(target: "engine", "extracted epoch set at #{}: {} addresses",
number, addresses.len());
@@ -452,7 +419,7 @@ impl ValidatorSet for ValidatorSafeContract {
}))
}
fn register_client(&self, client: Weak<EngineClient>) {
fn register_contract(&self, client: Weak<Client>) {
trace!(target: "engine", "Setting up contract caller.");
*self.client.write() = Some(client);
}
@@ -468,7 +435,7 @@ mod tests {
use spec::Spec;
use account_provider::AccountProvider;
use transaction::{Transaction, Action};
use client::BlockChainClient;
use client::{BlockChainClient, EngineClient};
use ethkey::Secret;
use miner::MinerService;
use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data};
@@ -479,7 +446,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("0000000000000000000000000000000000000005".parse::<Address>().unwrap()));
vc.register_client(Arc::downgrade(&client) as _);
vc.register_contract(Arc::downgrade(&client));
let last_hash = client.best_block_header().hash();
assert!(vc.contains(&last_hash, &"7d577a597b2742b498cb5cf0c26cdcd726d39e6e".parse::<Address>().unwrap()));
assert!(vc.contains(&last_hash, &"82a978b3f5962a5b0957d9ee9eef472ee55b42f1".parse::<Address>().unwrap()));
@@ -493,7 +460,7 @@ mod tests {
let v1 = tap.insert_account(keccak("0").into(), "").unwrap();
let chain_id = Spec::new_validator_safe_contract().chain_id();
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, Some(tap));
client.engine().register_client(Arc::downgrade(&client) as _);
client.engine().register_client(Arc::downgrade(&client));
let validator_contract = "0000000000000000000000000000000000000005".parse::<Address>().unwrap();
client.miner().set_engine_signer(v1, "".into()).unwrap();
@@ -507,7 +474,7 @@ mod tests {
data: "bfc708a000000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
}.sign(&s0, Some(chain_id));
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
::client::EngineClient::update_sealing(&*client);
client.update_sealing();
assert_eq!(client.chain_info().best_block_number, 1);
// Add "1" validator back in.
let tx = Transaction {
@@ -519,13 +486,13 @@ mod tests {
data: "4d238c8e00000000000000000000000082a978b3f5962a5b0957d9ee9eef472ee55b42f1".from_hex().unwrap(),
}.sign(&s0, Some(chain_id));
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
::client::EngineClient::update_sealing(&*client);
client.update_sealing();
// 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::EngineClient::update_sealing(&*client);
client.update_sealing();
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();
@@ -538,13 +505,13 @@ mod tests {
data: Vec::new(),
}.sign(&s0, Some(chain_id));
client.miner().import_own_transaction(client.as_ref(), tx.into()).unwrap();
::client::EngineClient::update_sealing(&*client);
client.update_sealing();
// 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) as _);
sync_client.engine().register_client(Arc::downgrade(&sync_client));
for i in 1..4 {
sync_client.import_block(client.block(BlockId::Number(i)).unwrap().into_inner()).unwrap();
}