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

@@ -43,7 +43,7 @@ use client::ancient_import::AncientVerifier;
use client::Error as ClientError;
use client::{
BlockId, TransactionId, UncleId, TraceId, ClientConfig, BlockChainClient,
MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode,
MiningBlockChainClient, EngineClient, TraceFilter, CallAnalytics, BlockImportError, Mode,
ChainNotify, PruningInfo, ProvingBlockChainClient,
};
use encoded;
@@ -771,7 +771,7 @@ impl Client {
res.map(|(output, proof)| (output, proof.into_iter().map(|x| x.into_vec()).collect()))
};
match with_state.generate_proof(&call) {
match (with_state)(&call) {
Ok(proof) => proof,
Err(e) => {
warn!(target: "client", "Failed to generate transition proof for block {}: {}", hash, e);
@@ -1132,7 +1132,9 @@ impl Client {
T: trace::Tracer,
V: trace::VMTracer,
{
let options = options.dont_check_nonce();
let options = options
.dont_check_nonce()
.save_output_from_contract();
let original_state = if state_diff { Some(state.clone()) } else { None };
let mut ret = Executive::new(state, env_info, engine).transact_virtual(transaction, options)?;
@@ -1935,7 +1937,7 @@ impl MiningBlockChainClient for Client {
}
}
impl super::traits::EngineClient for Client {
impl EngineClient for Client {
fn update_sealing(&self) {
self.miner.update_sealing(self)
}
@@ -1953,22 +1955,6 @@ impl super::traits::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<Bytes, String> {
BlockChainClient::call_contract(self, id, address, data)
}
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError> {
BlockChainClient::transact_contract(self, address, data)
}
fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
BlockChainClient::block_number(self, id)
}
}
impl ProvingBlockChainClient for Client {
@@ -1983,29 +1969,27 @@ impl ProvingBlockChainClient for Client {
}
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)> {
let (header, mut env_info) = match (self.block_header(id), self.env_info(id)) {
let (state, mut env_info) = match (self.state_at(id), self.env_info(id)) {
(Some(s), Some(e)) => (s, e),
_ => return None,
};
env_info.gas_limit = transaction.gas.clone();
let mut jdb = self.state_db.lock().journal_db().boxed_clone();
let backend = state::backend::Proving::new(jdb.as_hashdb_mut());
state::prove_transaction(
jdb.as_hashdb_mut(),
header.state_root().clone(),
&transaction,
&*self.engine,
&env_info,
self.factories.clone(),
false,
)
}
let mut state = state.replace_backend(backend);
let options = TransactOptions::with_no_tracing().dont_check_nonce();
let res = Executive::new(&mut state, &env_info, &*self.engine).transact(&transaction, options);
fn epoch_signal(&self, hash: H256) -> Option<Vec<u8>> {
// pending transitions are never deleted, and do not contain
// finality proofs by definition.
self.chain.read().get_pending_transition(hash).map(|pending| pending.proof)
match res {
Err(ExecutionError::Internal(_)) => None,
Err(e) => {
trace!(target: "client", "Proved call failed: {}", e);
Some((Vec::new(), state.drop().1.extract_proof()))
}
Ok(res) => Some((res.output, state.drop().1.extract_proof())),
}
}
}

View File

@@ -33,7 +33,7 @@ use devtools::*;
use transaction::{Transaction, LocalizedTransaction, PendingTransaction, SignedTransaction, Action};
use blockchain::TreeRoute;
use client::{
BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId,
BlockChainClient, MiningBlockChainClient, EngineClient, BlockChainInfo, BlockStatus, BlockId,
TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError,
ProvingBlockChainClient,
};
@@ -801,13 +801,9 @@ impl ProvingBlockChainClient for TestBlockChainClient {
fn prove_transaction(&self, _: SignedTransaction, _: BlockId) -> Option<(Bytes, Vec<DBValue>)> {
None
}
fn epoch_signal(&self, _: H256) -> Option<Vec<u8>> {
None
}
}
impl super::traits::EngineClient for TestBlockChainClient {
impl EngineClient for TestBlockChainClient {
fn update_sealing(&self) {
self.miner.update_sealing(self)
}
@@ -823,20 +819,4 @@ impl super::traits::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<Bytes, String> {
BlockChainClient::call_contract(self, id, address, data)
}
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError> {
BlockChainClient::transact_contract(self, address, data)
}
fn block_number(&self, id: BlockId) -> Option<BlockNumber> {
BlockChainClient::block_number(self, id)
}
}

View File

@@ -317,7 +317,7 @@ pub trait MiningBlockChainClient: BlockChainClient {
}
/// Client facilities used by internally sealing Engines.
pub trait EngineClient: Sync + Send {
pub trait EngineClient: MiningBlockChainClient {
/// Make a new block and seal it.
fn update_sealing(&self);
@@ -333,17 +333,6 @@ pub trait EngineClient: Sync + Send {
///
/// 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<Bytes, String>;
/// Import a transaction: used for misbehaviour reporting.
fn transact_contract(&self, address: Address, data: Bytes) -> Result<TransactionImportResult, EthcoreError>;
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
}
/// Extended client interface for providing proofs of the state.
@@ -363,7 +352,4 @@ pub trait ProvingBlockChainClient: BlockChainClient {
/// Returns the output of the call and a vector of database items necessary
/// to reproduce it.
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<(Bytes, Vec<DBValue>)>;
/// Get an epoch change signal by block hash.
fn epoch_signal(&self, hash: H256) -> Option<Vec<u8>>;
}

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();
}

View File

@@ -77,6 +77,8 @@ pub struct TransactOptions<T, V> {
pub vm_tracer: V,
/// Check transaction nonce before execution.
pub check_nonce: bool,
/// Records the output from init contract calls.
pub output_from_init_contract: bool,
}
impl<T, V> TransactOptions<T, V> {
@@ -86,6 +88,7 @@ impl<T, V> TransactOptions<T, V> {
tracer,
vm_tracer,
check_nonce: true,
output_from_init_contract: false,
}
}
@@ -94,6 +97,12 @@ impl<T, V> TransactOptions<T, V> {
self.check_nonce = false;
self
}
/// Saves the output from contract creation.
pub fn save_output_from_contract(mut self) -> Self {
self.output_from_init_contract = true;
self
}
}
impl TransactOptions<trace::ExecutiveTracer, trace::ExecutiveVMTracer> {
@@ -103,6 +112,7 @@ impl TransactOptions<trace::ExecutiveTracer, trace::ExecutiveVMTracer> {
tracer: trace::ExecutiveTracer::default(),
vm_tracer: trace::ExecutiveVMTracer::toplevel(),
check_nonce: true,
output_from_init_contract: false,
}
}
}
@@ -114,6 +124,7 @@ impl TransactOptions<trace::ExecutiveTracer, trace::NoopVMTracer> {
tracer: trace::ExecutiveTracer::default(),
vm_tracer: trace::NoopVMTracer,
check_nonce: true,
output_from_init_contract: false,
}
}
}
@@ -125,6 +136,7 @@ impl TransactOptions<trace::NoopTracer, trace::ExecutiveVMTracer> {
tracer: trace::NoopTracer,
vm_tracer: trace::ExecutiveVMTracer::toplevel(),
check_nonce: true,
output_from_init_contract: false,
}
}
}
@@ -136,6 +148,7 @@ impl TransactOptions<trace::NoopTracer, trace::NoopVMTracer> {
tracer: trace::NoopTracer,
vm_tracer: trace::NoopVMTracer,
check_nonce: true,
output_from_init_contract: false,
}
}
}
@@ -204,7 +217,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
pub fn transact<T, V>(&'a mut self, t: &SignedTransaction, options: TransactOptions<T, V>)
-> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer,
{
self.transact_with_tracer(t, options.check_nonce, options.tracer, options.vm_tracer)
self.transact_with_tracer(t, options.check_nonce, options.output_from_init_contract, options.tracer, options.vm_tracer)
}
/// Execute a transaction in a "virtual" context.
@@ -229,6 +242,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
&'a mut self,
t: &SignedTransaction,
check_nonce: bool,
output_from_create: bool,
mut tracer: T,
mut vm_tracer: V
) -> Result<Executed, ExecutionError> where T: Tracer, V: VMTracer {
@@ -297,7 +311,8 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
data: None,
call_type: CallType::None,
};
(self.create(params, &mut substate, &mut tracer, &mut vm_tracer), vec![])
let mut out = if output_from_create { Some(vec![]) } else { None };
(self.create(params, &mut substate, &mut out, &mut tracer, &mut vm_tracer), out.unwrap_or_else(Vec::new))
},
Action::Call(ref address) => {
let params = ActionParams {
@@ -490,6 +505,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
&mut self,
params: ActionParams,
substate: &mut Substate,
output: &mut Option<Bytes>,
tracer: &mut T,
vm_tracer: &mut V,
) -> vm::Result<(U256, ReturnData)> where T: Tracer, V: VMTracer {
@@ -531,7 +547,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
let mut subvmtracer = vm_tracer.prepare_subtrace(params.code.as_ref().expect("two ways into create (Externalities::create and Executive::transact_with_tracer); both place `Some(...)` `code` in `params`; qed"));
let res = {
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(trace_output.as_mut()), &mut subtracer, &mut subvmtracer)
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract(output.as_mut().or(trace_output.as_mut())), &mut subtracer, &mut subvmtracer)
};
vm_tracer.done_subtrace(subvmtracer);
@@ -540,7 +556,7 @@ impl<'a, B: 'a + StateBackend, E: Engine + ?Sized> Executive<'a, B, E> {
Ok(ref res) => tracer.trace_create(
trace_info,
gas - res.gas_left,
trace_output,
trace_output.map(|data| output.as_ref().map(|out| out.to_vec()).unwrap_or(data)),
created,
subtracer.drain()
),
@@ -701,7 +717,7 @@ mod tests {
let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
};
assert_eq!(gas_left, U256::from(79_975));
@@ -759,7 +775,7 @@ mod tests {
let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
};
assert_eq!(gas_left, U256::from(62_976));
@@ -926,7 +942,7 @@ mod tests {
let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params.clone(), &mut substate, &mut tracer, &mut vm_tracer).unwrap()
ex.create(params.clone(), &mut substate, &mut None, &mut tracer, &mut vm_tracer).unwrap()
};
assert_eq!(gas_left, U256::from(96_776));
@@ -1011,7 +1027,7 @@ mod tests {
let (gas_left, _) = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap()
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap()
};
assert_eq!(gas_left, U256::from(62_976));
@@ -1062,7 +1078,7 @@ mod tests {
{
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer).unwrap();
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer).unwrap();
}
assert_eq!(substate.contracts_created.len(), 1);
@@ -1335,7 +1351,7 @@ mod tests {
let result = {
let mut ex = Executive::new(&mut state, &info, &engine);
ex.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer)
ex.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer)
};
match result {

View File

@@ -224,7 +224,7 @@ impl<'a, T: 'a, V: 'a, B: 'a, E: 'a> Ext for Externalities<'a, T, V, B, E>
let mut ex = Executive::from_parent(self.state, self.env_info, self.engine, self.depth, self.static_flag);
// TODO: handle internal error separately
match ex.create(params, self.substate, self.tracer, self.vm_tracer) {
match ex.create(params, self.substate, &mut None, self.tracer, self.vm_tracer) {
Ok((gas_left, _)) => {
self.substate.contracts_created.push(address.clone());
ContractCreateResult::Created(address, gas_left)

View File

@@ -261,13 +261,8 @@ impl Header {
s.out()
}
/// Get the SHA3 (Keccak) of this header, optionally `with_seal`.
/// Get the KECCAK (Keccak) of this header, optionally `with_seal`.
pub fn rlp_keccak(&self, with_seal: Seal) -> H256 { keccak(self.rlp(with_seal)) }
/// Encode the header, getting a type-safe wrapper around the RLP.
pub fn encoded(&self) -> ::encoded::Header {
::encoded::Header::new(self.rlp(Seal::With))
}
}
impl Decodable for Header {

View File

@@ -116,7 +116,7 @@ impl ClientService {
});
io_service.register_handler(client_io)?;
spec.engine.register_client(Arc::downgrade(&client) as _);
spec.engine.register_client(Arc::downgrade(&client));
let stop_guard = ::devtools::StopGuard::new();
run_ipc(ipc_path, client.clone(), snapshot.clone(), stop_guard.share());

View File

@@ -93,7 +93,7 @@ fn make_chain(accounts: Arc<AccountProvider>, blocks_beyond: usize, transitions:
let mut cur_signers = vec![*RICH_ADDR];
{
let engine = client.engine();
engine.register_client(Arc::downgrade(&client) as _);
engine.register_client(Arc::downgrade(&client));
}
{

View File

@@ -36,6 +36,7 @@ use factory::Factories;
use header::{BlockNumber, Header};
use pod_state::*;
use rlp::{Rlp, RlpStream};
use state_db::StateDB;
use state::{Backend, State, Substate};
use state::backend::Basic as BasicBackend;
use trace::{NoopTracer, NoopVMTracer};
@@ -355,7 +356,7 @@ impl Spec {
{
let mut exec = Executive::new(&mut state, &env_info, self.engine.as_ref());
if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) {
if let Err(e) = exec.create(params, &mut substate, &mut None, &mut NoopTracer, &mut NoopVMTracer) {
warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
}
}
@@ -464,7 +465,7 @@ impl Spec {
}
/// Ensure that the given state DB has the trie nodes in for the genesis state.
pub fn ensure_db_good<T: Backend>(&self, db: T, factories: &Factories) -> Result<T, Error> {
pub fn ensure_db_good(&self, db: StateDB, factories: &Factories) -> Result<StateDB, Error> {
if db.as_hashdb().contains(&self.state_root()) {
return Ok(db)
}
@@ -486,63 +487,6 @@ impl Spec {
.and_then(|x| load_from(cache_dir, x).map_err(fmt))
}
/// initialize genesis epoch data, using in-memory database for
/// constructor.
pub fn genesis_epoch_data(&self) -> Result<Vec<u8>, String> {
use transaction::{Action, Transaction};
use util::{journaldb, kvdb};
let genesis = self.genesis_header();
let factories = Default::default();
let mut db = journaldb::new(
Arc::new(kvdb::in_memory(0)),
journaldb::Algorithm::Archive,
None,
);
self.ensure_db_good(BasicBackend(db.as_hashdb_mut()), &factories)
.map_err(|e| format!("Unable to initialize genesis state: {}", e))?;
let call = |a, d| {
let mut db = db.boxed_clone();
let env_info = ::evm::EnvInfo {
number: 0,
author: *genesis.author(),
timestamp: genesis.timestamp(),
difficulty: *genesis.difficulty(),
gas_limit: *genesis.gas_limit(),
last_hashes: Arc::new(Vec::new()),
gas_used: 0.into()
};
let from = Address::default();
let tx = Transaction {
nonce: self.engine.account_start_nonce(0),
action: Action::Call(a),
gas: U256::from(50_000_000), // TODO: share with client.
gas_price: U256::default(),
value: U256::default(),
data: d,
}.fake_sign(from);
let res = ::state::prove_transaction(
db.as_hashdb_mut(),
*genesis.state_root(),
&tx,
&*self.engine,
&env_info,
factories.clone(),
true,
);
res.map(|(out, proof)| (out, proof.into_iter().map(|x| x.into_vec()).collect()))
.ok_or_else(|| "Failed to prove call: insufficient state".into())
};
self.engine.genesis_epoch_data(&genesis, &call)
}
/// Create a new Spec which conforms to the Frontier-era Morden chain except that it's a NullEngine consensus.
pub fn new_test() -> Spec { load_bundled!("null_morden") }

View File

@@ -212,7 +212,8 @@ pub fn check_proof(
Err(_) => return ProvedExecution::BadProof,
};
match state.execute(env_info, engine, transaction, TransactOptions::with_no_tracing(), true) {
let options = TransactOptions::with_no_tracing().save_output_from_contract();
match state.execute(env_info, engine, transaction, options, true) {
Ok(executed) => ProvedExecution::Complete(executed),
Err(ExecutionError::Internal(_)) => ProvedExecution::BadProof,
Err(e) => ProvedExecution::Failed(e),
@@ -246,7 +247,7 @@ pub fn prove_transaction<H: AsHashDB + Send + Sync>(
Err(_) => return None,
};
let options = TransactOptions::with_no_tracing().dont_check_nonce();
let options = TransactOptions::with_no_tracing().dont_check_nonce().save_output_from_contract();
match state.execute(env_info, engine, transaction, options, virt) {
Err(ExecutionError::Internal(_)) => None,
Err(e) => {

View File

@@ -21,7 +21,8 @@ use std::collections::HashMap;
use std::collections::hash_map::Entry;
use native_contracts::TransactAcl as Contract;
use client::{BlockChainClient, BlockId, ChainNotify};
use util::{Address, H256, Bytes};
use util::{Address, Bytes};
use bigint::hash::H256;
use parking_lot::{Mutex, RwLock};
use futures::{self, Future};
use spec::CommonParams;