`Client` refactoring (#7038)

* Improves `BestBlock` comment

* Improves `TraceDB` comment

* Improves `journaldb::Algorithm` comment.

Probably the whole enum should be renamed to `Strategy` or something alike.

* Comments some of the `Client`'s fields

* Deglobs client imports

* Fixes comments

* Extracts `import_lock` to `Importer` struct

* Extracts `verifier` to `Importer` struct

* Extracts `block_queue` to `Importer` struct

* Extracts `miner` to `Importer` struct

* Extracts `ancient_verifier` to `Importer` struct

* Extracts `rng` to `Importer` struct

* Extracts `import_old_block` to `Importer` struct

* Adds `Nonce` trait

* Adds `Balance` trait

* Adds `ChainInfo` trait

* Fixes imports for tests using `chain_info` method

* Adds `BlockInfo` trait

* Adds more `ChainInfo` imports

* Adds `BlockInfo` imports

* Adds `ReopenBlock` trait

* Adds `PrepareOpenBlock` trait

* Fixes import in tests

* Adds `CallContract` trait

* Fixes imports in tests using `call_contract` method

* Adds `TransactionInfo` trait

* Adds `RegistryInfo` trait

* Fixes imports in tests using `registry_address` method

* Adds `ScheduleInfo` trait

* Adds `ImportSealedBlock` trait

* Fixes imports in test using `import_sealed_block` method

* Adds `BroadcastProposalBlock` trait

* Migrates `Miner` to static dispatch

* Fixes tests

* Moves `calculate_enacted_retracted` to `Importer`

* Moves import-related methods to `Importer`

* Removes redundant `import_old_block` wrapper

* Extracts `import_block*` into separate trait

* Fixes tests

* Handles `Pending` in `LightFetch`

* Handles `Pending` in filters

* Handles `Pending` in `ParityClient`

* Handles `Pending` in `EthClient`

* Removes `BlockId::Pending`, partly refactors dependent code

* Adds `StateInfo` trait

* Exports `StateOrBlock` and `BlockChain` types from `client` module

* Refactors `balance` RPC using generic API

* Refactors `storage_at` RPC using generic API

* Makes `MinerService::pending_state`'s return type dynamic

* Adds `StateOrBlock` and `BlockChain` types

* Adds impl of `client::BlockChain` for `Client`

* Exports `StateInfo` trait from `client` module

* Missing `self` use

To be fixed up to "Adds impl of `client::BlockChain` for `Client`"

* Adds `number_to_id` and refactors dependent RPC methods

* Refactors `code_at` using generic API

* Adds `StateClient` trait

* Refactors RPC to use `StateClient` trait

* Reverts `client::BlockChain` trait stuff, refactors methods to accept `StateOrBlock`

* Refactors TestClient

* Adds helper function `block_number_to_id`

* Uses `block_number_to_id` instead of local function

* Handles `Pending` in `list_accounts` and `list_storage_keys`

* Attempt to use associated types for state instead of trait objects

* Simplifies `state_at_beginning`

* Extracts `call` and `call_many` into separate trait

* Refactors `build_last_hashes` to accept reference

* Exports `Call` type from the module

* Refactors `call` and `call_many` to accept state and header

* Exports `state_at` in `StateClient`

* Exports `pending_block_header` from `MinerService`

* Refactors RPC `call` method using new API

* Adds missing parentheses

* Refactors `parity::call` to use new call API

* Update .gitlab-ci.yml

fix gitlab lint

* Fixes error handling

* Refactors `traces::call` and `call_many` to use new call API

* Refactors `call_contract`

* Refactors `block_header`

* Refactors internal RPC method `block`

* Moves `estimate_gas` to `Call` trait, refactors parameters

* Refactors `estimate_gas` in RPC

* Refactors `uncle`

* Refactors RPC `transaction`

* Covers missing branches

* Makes it all compile, fixes compiler grumbles

* Adds casts in `blockchain` module

* Fixes `PendingBlock` tests, work on `MinerService`

* Adds test stubs for StateClient and EngineInfo

* Makes `state_db` public

* Adds missing impls for `TestBlockChainClient`

* Adds trait documentation

* Adds missing docs to the `state_db` module

* Fixes trivial compilation errors

* Moves `code_hash` method to a `BlockInfo` trait

* Refactors `Verifier` to be generic over client

* Refactors `TransactionFilter` to be generic over client

* Refactors `Miner` and `Client` to reflect changes in verifier and txfilter API

* Moves `ServiceTransactionChecker` back to `ethcore`

* Fixes trait bounds in `Miner` API

* Fixes `Client`

* Fixes lifetime bound in `FullFamilyParams`

* Adds comments to `FullFamilyParams`

* Fixes imports in `ethcore`

* Fixes BlockNumber handling in `code_at` and `replay_block_transactions`

* fix compile issues

* First step to redundant trait merge

* Fixes compilation error in RPC tests

* Adds mock `State` as a stub for `TestClient`

* Handles `StateOrBlock::State` in `TestBlockChainClient::balance`

* Fixes `transaction_count` RPC

* Fixes `transaction_count`

* Moves `service_transaction.json` to the `contracts` subfolder

* Fixes compilation errors in tests

* Refactors client to use `AccountData`

* Refactors client to use `BlockChain`

* Refactors miner to use aggregate traits

* Adds `SealedBlockImporter` trait

* Refactors miner to use `SealedBlockImporter` trait

* Removes unused imports

* Simplifies `RegistryInfo::registry_address`

* Fixes indentation

* Removes commented out trait bound
This commit is contained in:
Dmitry Kashitsyn 2018-03-03 18:42:13 +01:00 committed by Marek Kotewicz
parent 81b52c7336
commit 9d7d6f7108
65 changed files with 2067 additions and 1238 deletions

1
Cargo.lock generated
View File

@ -2146,6 +2146,7 @@ dependencies = [
"parity-updater 1.9.0",
"parity-version 1.10.0",
"parking_lot 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"patricia-trie 0.1.0",
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rlp 0.2.1",

View File

@ -497,7 +497,7 @@ impl HeaderChain {
if self.best_block.read().number < num { return None }
self.candidates.read().get(&num).map(|entry| entry.canonical_hash)
}
BlockId::Latest | BlockId::Pending => {
BlockId::Latest => {
Some(self.best_block.read().hash)
}
}
@ -539,7 +539,7 @@ impl HeaderChain {
self.candidates.read().get(&num).map(|entry| entry.canonical_hash)
.and_then(load_from_db)
}
BlockId::Latest | BlockId::Pending => {
BlockId::Latest => {
// hold candidates hear to prevent deletion of the header
// as we read it.
let _candidates = self.candidates.read();
@ -575,7 +575,7 @@ impl HeaderChain {
if self.best_block.read().number < num { return None }
candidates.get(&num).map(|era| era.candidates[0].total_difficulty)
}
BlockId::Latest | BlockId::Pending => Some(self.best_block.read().total_difficulty)
BlockId::Latest => Some(self.best_block.read().total_difficulty)
}
}
@ -866,7 +866,6 @@ mod tests {
assert!(chain.block_header(BlockId::Earliest).is_some());
assert!(chain.block_header(BlockId::Latest).is_some());
assert!(chain.block_header(BlockId::Pending).is_some());
}
#[test]

View File

@ -574,6 +574,12 @@ impl<T: ChainDataFetcher> LightChainClient for Client<T> {
}
}
impl<T: ChainDataFetcher> ::ethcore::client::ChainInfo for Client<T> {
fn chain_info(&self) -> BlockChainInfo {
Client::chain_info(self)
}
}
impl<T: ChainDataFetcher> ::ethcore::client::EngineClient for Client<T> {
fn update_sealing(&self) { }
fn submit_seal(&self, _block_hash: H256, _seal: Vec<Vec<u8>>) { }
@ -587,10 +593,6 @@ impl<T: ChainDataFetcher> ::ethcore::client::EngineClient for Client<T> {
})
}
fn chain_info(&self) -> BlockChainInfo {
Client::chain_info(self)
}
fn as_full_client(&self) -> Option<&::ethcore::client::BlockChainClient> {
None
}

View File

@ -948,7 +948,7 @@ mod tests {
use trie::recorder::Recorder;
use hash::keccak;
use ethcore::client::{BlockChainClient, TestBlockChainClient, EachBlockWith};
use ethcore::client::{BlockChainClient, BlockInfo, TestBlockChainClient, EachBlockWith};
use ethcore::header::Header;
use ethcore::encoded;
use ethcore::receipt::{Receipt, TransactionOutcome};

View File

@ -20,9 +20,9 @@
use std::sync::Arc;
use ethcore::blockchain_info::BlockChainInfo;
use ethcore::client::{BlockChainClient, ProvingBlockChainClient};
use ethcore::encoded;
use ethcore::client::{BlockChainClient, ProvingBlockChainClient, ChainInfo, BlockInfo as ClientBlockInfo};
use ethcore::ids::BlockId;
use ethcore::encoded;
use ethereum_types::H256;
use parking_lot::RwLock;
use transaction::PendingTransaction;
@ -138,7 +138,7 @@ pub trait Provider: Send + Sync {
// Implementation of a light client data provider for a client.
impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
fn chain_info(&self) -> BlockChainInfo {
BlockChainClient::chain_info(self)
ChainInfo::chain_info(self)
}
fn reorg_depth(&self, a: &H256, b: &H256) -> Option<u64> {
@ -150,7 +150,7 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
}
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
BlockChainClient::block_header(self, id)
ClientBlockInfo::block_header(self, id)
}
fn transaction_index(&self, req: request::CompleteTransactionIndexRequest)

View File

@ -18,7 +18,12 @@ use ethereum_types::{H256, U256};
use bytes::Bytes;
use header::BlockNumber;
/// Best block info.
/// Contains information on a best block that is specific to the consensus engine.
///
/// For GHOST fork-choice rule it would typically describe the block with highest
/// combined difficulty (usually the block with the highest block number).
///
/// Sometimes refered as 'latest block'.
#[derive(Default)]
pub struct BestBlock {
/// Best block hash.

File diff suppressed because it is too large Load Diff

View File

@ -30,9 +30,12 @@ pub use self::error::Error;
pub use self::evm_test_client::{EvmTestClient, EvmTestError, TransactResult};
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
pub use self::chain_notify::ChainNotify;
pub use self::traits::{BlockChainClient, MiningBlockChainClient, EngineClient};
pub use self::traits::ProvingBlockChainClient;
pub use self::traits::{
Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, PrepareOpenBlock, CallContract, TransactionInfo, RegistryInfo, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock,
StateOrBlock, StateClient, Call, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter
};
pub use state::StateInfo;
pub use self::traits::{BlockChainClient, MiningBlockChainClient, EngineClient, ProvingBlockChainClient};
pub use types::ids::*;
pub use types::trace_filter::Filter as TraceFilter;

View File

@ -34,9 +34,11 @@ use ethkey::{Generator, Random};
use transaction::{self, Transaction, LocalizedTransaction, PendingTransaction, SignedTransaction, Action};
use blockchain::{TreeRoute, BlockReceipts};
use client::{
BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId,
Nonce, Balance, ChainInfo, BlockInfo, ReopenBlock, CallContract, TransactionInfo, RegistryInfo,
PrepareOpenBlock, BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockId,
TransactionId, UncleId, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError,
ProvingBlockChainClient,
ProvingBlockChainClient, ScheduleInfo, ImportSealedBlock, BroadcastProposalBlock, ImportBlock, StateOrBlock,
Call, StateClient, EngineInfo, AccountData, BlockChain, BlockProducer, SealedBlockImporter
};
use db::{NUM_COLUMNS, COL_STATE};
use header::{Header as BlockHeader, BlockNumber};
@ -59,7 +61,11 @@ use executive::Executed;
use error::CallError;
use trace::LocalizedTrace;
use state_db::StateDB;
use header::Header;
use encoded;
use engines::EthEngine;
use trie;
use state::StateInfo;
/// Test client.
pub struct TestBlockChainClient {
@ -316,7 +322,7 @@ impl TestBlockChainClient {
BlockId::Hash(hash) => Some(hash),
BlockId::Number(n) => self.numbers.read().get(&(n as usize)).cloned(),
BlockId::Earliest => self.numbers.read().get(&0).cloned(),
BlockId::Latest | BlockId::Pending => self.numbers.read().get(&(self.numbers.read().len() - 1)).cloned()
BlockId::Latest => self.numbers.read().get(&(self.numbers.read().len() - 1)).cloned()
}
}
@ -357,13 +363,13 @@ pub fn get_temp_state_db() -> StateDB {
StateDB::new(journal_db, 1024 * 1024)
}
impl MiningBlockChainClient for TestBlockChainClient {
fn as_block_chain_client(&self) -> &BlockChainClient { self }
fn latest_schedule(&self) -> Schedule {
Schedule::new_post_eip150(24576, true, true, true)
impl ReopenBlock for TestBlockChainClient {
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
block.reopen(&*self.spec.engine)
}
}
impl PrepareOpenBlock for TestBlockChainClient {
fn prepare_open_block(&self, author: Address, gas_range_target: (U256, U256), extra_data: Bytes) -> OpenBlock {
let engine = &*self.spec.engine;
let genesis_header = self.spec.genesis_header();
@ -386,39 +392,221 @@ impl MiningBlockChainClient for TestBlockChainClient {
open_block.set_timestamp(*self.latest_block_timestamp.read());
open_block
}
}
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock {
block.reopen(&*self.spec.engine)
}
fn vm_factory(&self) -> &VmFactory {
&self.vm_factory
impl ScheduleInfo for TestBlockChainClient {
fn latest_schedule(&self) -> Schedule {
Schedule::new_post_eip150(24576, true, true, true)
}
}
impl ImportSealedBlock for TestBlockChainClient {
fn import_sealed_block(&self, _block: SealedBlock) -> ImportResult {
Ok(H256::default())
}
}
impl BlockProducer for TestBlockChainClient {}
impl BroadcastProposalBlock for TestBlockChainClient {
fn broadcast_proposal_block(&self, _block: SealedBlock) {}
}
impl BlockChainClient for TestBlockChainClient {
fn call(&self, _t: &SignedTransaction, _analytics: CallAnalytics, _block: BlockId) -> Result<Executed, CallError> {
impl SealedBlockImporter for TestBlockChainClient {}
impl MiningBlockChainClient for TestBlockChainClient {
fn vm_factory(&self) -> &VmFactory {
&self.vm_factory
}
}
impl Nonce for TestBlockChainClient {
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> {
match id {
BlockId::Latest => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params().account_start_nonce)),
_ => None,
}
}
fn latest_nonce(&self, address: &Address) -> U256 {
self.nonce(address, BlockId::Latest).unwrap()
}
}
impl Balance for TestBlockChainClient {
fn balance(&self, address: &Address, state: StateOrBlock) -> Option<U256> {
match state {
StateOrBlock::Block(BlockId::Latest) | StateOrBlock::State(_) => Some(self.balances.read().get(address).cloned().unwrap_or_else(U256::zero)),
_ => None,
}
}
fn latest_balance(&self, address: &Address) -> U256 {
self.balance(address, BlockId::Latest.into()).unwrap()
}
}
impl AccountData for TestBlockChainClient {}
impl ChainInfo for TestBlockChainClient {
fn chain_info(&self) -> BlockChainInfo {
let number = self.blocks.read().len() as BlockNumber - 1;
BlockChainInfo {
total_difficulty: *self.difficulty.read(),
pending_total_difficulty: *self.difficulty.read(),
genesis_hash: self.genesis_hash.clone(),
best_block_hash: self.last_hash.read().clone(),
best_block_number: number,
best_block_timestamp: number,
first_block_hash: self.first_block.read().as_ref().map(|x| x.0),
first_block_number: self.first_block.read().as_ref().map(|x| x.1),
ancient_block_hash: self.ancient_block.read().as_ref().map(|x| x.0),
ancient_block_number: self.ancient_block.read().as_ref().map(|x| x.1)
}
}
}
impl BlockInfo for TestBlockChainClient {
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
self.block_hash(id)
.and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec()))
.map(encoded::Header::new)
}
fn best_block_header(&self) -> encoded::Header {
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
.expect("Best block always has header.")
}
fn block(&self, id: BlockId) -> Option<encoded::Block> {
self.block_hash(id)
.and_then(|hash| self.blocks.read().get(&hash).cloned())
.map(encoded::Block::new)
}
fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256> {
match id {
BlockId::Latest => self.code.read().get(address).map(|c| keccak(&c)),
_ => None,
}
}
}
impl CallContract for TestBlockChainClient {
fn call_contract(&self, _id: BlockId, _address: Address, _data: Bytes) -> Result<Bytes, String> { Ok(vec![]) }
}
impl TransactionInfo for TestBlockChainClient {
fn transaction_block(&self, _id: TransactionId) -> Option<H256> {
None // Simple default.
}
}
impl BlockChain for TestBlockChainClient {}
impl RegistryInfo for TestBlockChainClient {
fn registry_address(&self, _name: String, _block: BlockId) -> Option<Address> { None }
}
impl ImportBlock for TestBlockChainClient {
fn import_block(&self, b: Bytes) -> Result<H256, BlockImportError> {
let header = Rlp::new(&b).val_at::<BlockHeader>(0);
let h = header.hash();
let number: usize = header.number() as usize;
if number > self.blocks.read().len() {
panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().len(), number);
}
if number > 0 {
match self.blocks.read().get(header.parent_hash()) {
Some(parent) => {
let parent = Rlp::new(parent).val_at::<BlockHeader>(0);
if parent.number() != (header.number() - 1) {
panic!("Unexpected block parent");
}
},
None => {
panic!("Unknown block parent {:?} for block {}", header.parent_hash(), number);
}
}
}
let len = self.numbers.read().len();
if number == len {
{
let mut difficulty = self.difficulty.write();
*difficulty = *difficulty + header.difficulty().clone();
}
mem::replace(&mut *self.last_hash.write(), h.clone());
self.blocks.write().insert(h.clone(), b);
self.numbers.write().insert(number, h.clone());
let mut parent_hash = header.parent_hash().clone();
if number > 0 {
let mut n = number - 1;
while n > 0 && self.numbers.read()[&n] != parent_hash {
*self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone();
n -= 1;
parent_hash = Rlp::new(&self.blocks.read()[&parent_hash]).val_at::<BlockHeader>(0).parent_hash().clone();
}
}
}
else {
self.blocks.write().insert(h.clone(), b.to_vec());
}
Ok(h)
}
fn import_block_with_receipts(&self, b: Bytes, _r: Bytes) -> Result<H256, BlockImportError> {
self.import_block(b)
}
}
impl Call for TestBlockChainClient {
// State will not be used by test client anyway, since all methods that accept state are mocked
type State = ();
fn call(&self, _t: &SignedTransaction, _analytics: CallAnalytics, _state: &mut Self::State, _header: &Header) -> Result<Executed, CallError> {
self.execution_result.read().clone().unwrap()
}
fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], block: BlockId) -> Result<Vec<Executed>, CallError> {
fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], state: &mut Self::State, header: &Header) -> Result<Vec<Executed>, CallError> {
let mut res = Vec::with_capacity(txs.len());
for &(ref tx, analytics) in txs {
res.push(self.call(tx, analytics, block)?);
res.push(self.call(tx, analytics, state, header)?);
}
Ok(res)
}
fn estimate_gas(&self, _t: &SignedTransaction, _block: BlockId) -> Result<U256, CallError> {
fn estimate_gas(&self, _t: &SignedTransaction, _state: &Self::State, _header: &Header) -> Result<U256, CallError> {
Ok(21000.into())
}
}
impl StateInfo for () {
fn nonce(&self, _address: &Address) -> trie::Result<U256> { unimplemented!() }
fn balance(&self, _address: &Address) -> trie::Result<U256> { unimplemented!() }
fn storage_at(&self, _address: &Address, _key: &H256) -> trie::Result<H256> { unimplemented!() }
fn code(&self, _address: &Address) -> trie::Result<Option<Arc<Bytes>>> { unimplemented!() }
}
impl StateClient for TestBlockChainClient {
// State will not be used by test client anyway, since all methods that accept state are mocked
type State = ();
fn latest_state(&self) -> Self::State {
()
}
fn state_at(&self, _id: BlockId) -> Option<Self::State> {
Some(())
}
}
impl EngineInfo for TestBlockChainClient {
fn engine(&self) -> &EthEngine {
unimplemented!()
}
}
impl BlockChainClient for TestBlockChainClient {
fn replay(&self, _id: TransactionId, _analytics: CallAnalytics) -> Result<Executed, CallError> {
self.execution_result.read().clone().unwrap()
}
@ -435,49 +623,20 @@ impl BlockChainClient for TestBlockChainClient {
Self::block_hash(self, id)
}
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256> {
match id {
BlockId::Latest | BlockId::Pending => Some(self.nonces.read().get(address).cloned().unwrap_or(self.spec.params().account_start_nonce)),
_ => None,
}
}
fn storage_root(&self, _address: &Address, _id: BlockId) -> Option<H256> {
None
}
fn latest_nonce(&self, address: &Address) -> U256 {
self.nonce(address, BlockId::Latest).unwrap()
}
fn code(&self, address: &Address, id: BlockId) -> Option<Option<Bytes>> {
match id {
BlockId::Latest | BlockId::Pending => Some(self.code.read().get(address).cloned()),
fn code(&self, address: &Address, state: StateOrBlock) -> Option<Option<Bytes>> {
match state {
StateOrBlock::Block(BlockId::Latest) => Some(self.code.read().get(address).cloned()),
_ => None,
}
}
fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256> {
match id {
BlockId::Latest | BlockId::Pending => self.code.read().get(address).map(|c| keccak(&c)),
_ => None,
}
}
fn balance(&self, address: &Address, id: BlockId) -> Option<U256> {
match id {
BlockId::Latest | BlockId::Pending => Some(self.balances.read().get(address).cloned().unwrap_or_else(U256::zero)),
_ => None,
}
}
fn latest_balance(&self, address: &Address) -> U256 {
self.balance(address, BlockId::Latest).unwrap()
}
fn storage_at(&self, address: &Address, position: &H256, id: BlockId) -> Option<H256> {
match id {
BlockId::Latest | BlockId::Pending => Some(self.storage.read().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new)),
fn storage_at(&self, address: &Address, position: &H256, state: StateOrBlock) -> Option<H256> {
match state {
StateOrBlock::Block(BlockId::Latest) => Some(self.storage.read().get(&(address.clone(), position.clone())).cloned().unwrap_or_else(H256::new)),
_ => None,
}
}
@ -493,10 +652,6 @@ impl BlockChainClient for TestBlockChainClient {
None // Simple default.
}
fn transaction_block(&self, _id: TransactionId) -> Option<H256> {
None // Simple default.
}
fn uncle(&self, _id: UncleId) -> Option<encoded::Header> {
None // Simple default.
}
@ -522,17 +677,6 @@ impl BlockChainClient for TestBlockChainClient {
unimplemented!();
}
fn best_block_header(&self) -> encoded::Header {
self.block_header(BlockId::Hash(self.chain_info().best_block_hash))
.expect("Best block always has header.")
}
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
self.block_hash(id)
.and_then(|hash| self.blocks.read().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec()))
.map(encoded::Header::new)
}
fn block_number(&self, _id: BlockId) -> Option<BlockNumber> {
unimplemented!()
}
@ -546,12 +690,6 @@ impl BlockChainClient for TestBlockChainClient {
}))
}
fn block(&self, id: BlockId) -> Option<encoded::Block> {
self.block_hash(id)
.and_then(|hash| self.blocks.read().get(&hash).cloned())
.map(encoded::Block::new)
}
fn block_extra_info(&self, id: BlockId) -> Option<BTreeMap<String, String>> {
self.block(id)
.map(|block| block.view().header())
@ -564,7 +702,6 @@ impl BlockChainClient for TestBlockChainClient {
BlockId::Number(number) if (number as usize) < self.blocks.read().len() => BlockStatus::InChain,
BlockId::Hash(ref hash) if self.blocks.read().get(hash).is_some() => BlockStatus::InChain,
BlockId::Latest | BlockId::Earliest => BlockStatus::InChain,
BlockId::Pending => BlockStatus::Pending,
_ => BlockStatus::Unknown,
}
}
@ -628,55 +765,6 @@ impl BlockChainClient for TestBlockChainClient {
None
}
fn import_block(&self, b: Bytes) -> Result<H256, BlockImportError> {
let header = Rlp::new(&b).val_at::<BlockHeader>(0);
let h = header.hash();
let number: usize = header.number() as usize;
if number > self.blocks.read().len() {
panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().len(), number);
}
if number > 0 {
match self.blocks.read().get(header.parent_hash()) {
Some(parent) => {
let parent = Rlp::new(parent).val_at::<BlockHeader>(0);
if parent.number() != (header.number() - 1) {
panic!("Unexpected block parent");
}
},
None => {
panic!("Unknown block parent {:?} for block {}", header.parent_hash(), number);
}
}
}
let len = self.numbers.read().len();
if number == len {
{
let mut difficulty = self.difficulty.write();
*difficulty = *difficulty + header.difficulty().clone();
}
mem::replace(&mut *self.last_hash.write(), h.clone());
self.blocks.write().insert(h.clone(), b);
self.numbers.write().insert(number, h.clone());
let mut parent_hash = header.parent_hash().clone();
if number > 0 {
let mut n = number - 1;
while n > 0 && self.numbers.read()[&n] != parent_hash {
*self.numbers.write().get_mut(&n).unwrap() = parent_hash.clone();
n -= 1;
parent_hash = Rlp::new(&self.blocks.read()[&parent_hash]).val_at::<BlockHeader>(0).parent_hash().clone();
}
}
}
else {
self.blocks.write().insert(h.clone(), b.to_vec());
}
Ok(h)
}
fn import_block_with_receipts(&self, b: Bytes, _r: Bytes) -> Result<H256, BlockImportError> {
self.import_block(b)
}
fn queue_info(&self) -> QueueInfo {
QueueInfo {
verified_queue_size: self.queue_size.load(AtomicOrder::Relaxed),
@ -695,22 +783,6 @@ impl BlockChainClient for TestBlockChainClient {
Default::default()
}
fn chain_info(&self) -> BlockChainInfo {
let number = self.blocks.read().len() as BlockNumber - 1;
BlockChainInfo {
total_difficulty: *self.difficulty.read(),
pending_total_difficulty: *self.difficulty.read(),
genesis_hash: self.genesis_hash.clone(),
best_block_hash: self.last_hash.read().clone(),
best_block_number: number,
best_block_timestamp: number,
first_block_hash: self.first_block.read().as_ref().map(|x| x.0),
first_block_number: self.first_block.read().as_ref().map(|x| x.1),
ancient_block_hash: self.ancient_block.read().as_ref().map(|x| x.0),
ancient_block_number: self.ancient_block.read().as_ref().map(|x| x.1)
}
}
fn filter_traces(&self, _filter: TraceFilter) -> Option<Vec<LocalizedTrace>> {
self.traces.read().clone()
}
@ -762,8 +834,6 @@ impl BlockChainClient for TestBlockChainClient {
}
}
fn call_contract(&self, _id: BlockId, _address: Address, _data: Bytes) -> Result<Bytes, String> { Ok(vec![]) }
fn transact_contract(&self, address: Address, data: Bytes) -> Result<transaction::ImportResult, EthcoreError> {
let transaction = Transaction {
nonce: self.latest_nonce(&self.miner.author()),
@ -781,8 +851,6 @@ impl BlockChainClient for TestBlockChainClient {
fn registrar_address(&self) -> Option<Address> { None }
fn registry_address(&self, _name: String, _block: BlockId) -> Option<Address> { None }
fn eip86_transition(&self) -> u64 { u64::max_value() }
}
@ -821,10 +889,6 @@ impl super::traits::EngineClient for TestBlockChainClient {
None
}
fn chain_info(&self) -> BlockChainInfo {
BlockChainClient::chain_info(self)
}
fn as_full_client(&self) -> Option<&BlockChainClient> { Some(self) }
fn block_number(&self, id: BlockId) -> Option<BlockNumber> {

View File

@ -32,6 +32,9 @@ use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
use transaction::{LocalizedTransaction, PendingTransaction, SignedTransaction, ImportResult as TransactionImportResult};
use verification::queue::QueueInfo as BlockQueueInfo;
use state::StateInfo;
use header::Header;
use engines::EthEngine;
use ethereum_types::{H256, U256, Address};
use bytes::Bytes;
@ -46,80 +49,198 @@ use types::block_status::BlockStatus;
use types::mode::Mode;
use types::pruning_info::PruningInfo;
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send {
/// State information to be used during client query
pub enum StateOrBlock {
/// State to be used, may be pending
State(Box<StateInfo>),
/// Get raw block header data by block id.
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
/// Id of an existing block from a chain to get state from
Block(BlockId)
}
/// Look up the block number for the given block ID.
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
impl<S: StateInfo + 'static> From<S> for StateOrBlock {
fn from(info: S) -> StateOrBlock {
StateOrBlock::State(Box::new(info) as Box<_>)
}
}
/// Get raw block body data by block id.
/// Block body is an RLP list of two items: uncles and transactions.
fn block_body(&self, id: BlockId) -> Option<encoded::Body>;
impl From<Box<StateInfo>> for StateOrBlock {
fn from(info: Box<StateInfo>) -> StateOrBlock {
StateOrBlock::State(info)
}
}
/// Get raw block data by block header hash.
fn block(&self, id: BlockId) -> Option<encoded::Block>;
/// Get block status by block header hash.
fn block_status(&self, id: BlockId) -> BlockStatus;
/// Get block total difficulty.
fn block_total_difficulty(&self, id: BlockId) -> Option<U256>;
impl From<BlockId> for StateOrBlock {
fn from(id: BlockId) -> StateOrBlock {
StateOrBlock::Block(id)
}
}
/// Provides `nonce` and `latest_nonce` methods
pub trait Nonce {
/// Attempt to get address nonce at given block.
/// May not fail on BlockId::Latest.
fn nonce(&self, address: &Address, id: BlockId) -> Option<U256>;
/// Attempt to get address storage root at given block.
/// May not fail on BlockId::Latest.
fn storage_root(&self, address: &Address, id: BlockId) -> Option<H256>;
/// Get address nonce at the latest block's state.
fn latest_nonce(&self, address: &Address) -> U256 {
self.nonce(address, BlockId::Latest)
.expect("nonce will return Some when given BlockId::Latest. nonce was given BlockId::Latest. \
Therefore nonce has returned Some; qed")
}
}
/// Provides `balance` and `latest_balance` methods
pub trait Balance {
/// Get address balance at the given block's state.
///
/// May not return None if given BlockId::Latest.
/// Returns None if and only if the block's root hash has been pruned from the DB.
fn balance(&self, address: &Address, state: StateOrBlock) -> Option<U256>;
/// Get address balance at the latest block's state.
fn latest_balance(&self, address: &Address) -> U256 {
self.balance(address, BlockId::Latest.into())
.expect("balance will return Some if given BlockId::Latest. balance was given BlockId::Latest \
Therefore balance has returned Some; qed")
}
}
/// Provides methods to access account info
pub trait AccountData: Nonce + Balance {}
/// Provides `chain_info` method
pub trait ChainInfo {
/// Get blockchain information.
fn chain_info(&self) -> BlockChainInfo;
}
/// Provides various information on a block by it's ID
pub trait BlockInfo {
/// Get raw block header data by block id.
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
/// Get the best block header.
fn best_block_header(&self) -> encoded::Header;
/// Get raw block data by block header hash.
fn block(&self, id: BlockId) -> Option<encoded::Block>;
/// Get address code hash at given block's state.
fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256>;
}
/// Provides various information on a transaction by it's ID
pub trait TransactionInfo {
/// Get the hash of block that contains the transaction, if any.
fn transaction_block(&self, id: TransactionId) -> Option<H256>;
}
/// Provides methods to access chain state
pub trait StateClient {
/// Type representing chain state
type State: StateInfo;
/// Get a copy of the best block's state.
fn latest_state(&self) -> Self::State;
/// Attempt to get a copy of a specific block's final state.
///
/// This will not fail if given BlockId::Latest.
/// Otherwise, this can fail (but may not) if the DB prunes state or the block
/// is unknown.
fn state_at(&self, id: BlockId) -> Option<Self::State>;
}
/// Provides various blockchain information, like block header, chain state etc.
pub trait BlockChain: ChainInfo + BlockInfo + TransactionInfo {}
/// Provides information on a blockchain service and it's registry
pub trait RegistryInfo {
/// Get the address of a particular blockchain service, if available.
fn registry_address(&self, name: String, block: BlockId) -> Option<Address>;
}
// FIXME Why these methods belong to BlockChainClient and not MiningBlockChainClient?
/// Provides methods to import block into blockchain
pub trait ImportBlock {
/// Import a block into the blockchain.
fn import_block(&self, bytes: Bytes) -> Result<H256, BlockImportError>;
/// Import a block with transaction receipts. Does no sealing and transaction validation.
fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result<H256, BlockImportError>;
}
/// Provides `call_contract` method
pub trait CallContract {
/// Like `call`, but with various defaults. Designed to be used for calling contracts.
fn call_contract(&self, id: BlockId, address: Address, data: Bytes) -> Result<Bytes, String>;
}
/// Provides `call` and `call_many` methods
pub trait Call {
/// Type representing chain state
type State: StateInfo;
/// Makes a non-persistent transaction call.
fn call(&self, tx: &SignedTransaction, analytics: CallAnalytics, state: &mut Self::State, header: &Header) -> Result<Executed, CallError>;
/// Makes multiple non-persistent but dependent transaction calls.
/// Returns a vector of successes or a failure if any of the transaction fails.
fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], state: &mut Self::State, header: &Header) -> Result<Vec<Executed>, CallError>;
/// Estimates how much gas will be necessary for a call.
fn estimate_gas(&self, t: &SignedTransaction, state: &Self::State, header: &Header) -> Result<U256, CallError>;
}
/// Provides `engine` method
pub trait EngineInfo {
/// Get underlying engine object
fn engine(&self) -> &EthEngine;
}
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContract + RegistryInfo + ImportBlock {
/// Look up the block number for the given block ID.
fn block_number(&self, id: BlockId) -> Option<BlockNumber>;
/// Get raw block body data by block id.
/// Block body is an RLP list of two items: uncles and transactions.
fn block_body(&self, id: BlockId) -> Option<encoded::Body>;
/// Get block status by block header hash.
fn block_status(&self, id: BlockId) -> BlockStatus;
/// Get block total difficulty.
fn block_total_difficulty(&self, id: BlockId) -> Option<U256>;
/// Attempt to get address storage root at given block.
/// May not fail on BlockId::Latest.
fn storage_root(&self, address: &Address, id: BlockId) -> Option<H256>;
/// Get block hash.
fn block_hash(&self, id: BlockId) -> Option<H256>;
/// Get address code at given block's state.
fn code(&self, address: &Address, id: BlockId) -> Option<Option<Bytes>>;
fn code(&self, address: &Address, state: StateOrBlock) -> Option<Option<Bytes>>;
/// Get address code at the latest block's state.
fn latest_code(&self, address: &Address) -> Option<Bytes> {
self.code(address, BlockId::Latest)
self.code(address, BlockId::Latest.into())
.expect("code will return Some if given BlockId::Latest; qed")
}
/// Get address code hash at given block's state.
fn code_hash(&self, address: &Address, id: BlockId) -> Option<H256>;
/// Get address balance at the given block's state.
///
/// May not return None if given BlockId::Latest.
/// Returns None if and only if the block's root hash has been pruned from the DB.
fn balance(&self, address: &Address, id: BlockId) -> Option<U256>;
/// Get address balance at the latest block's state.
fn latest_balance(&self, address: &Address) -> U256 {
self.balance(address, BlockId::Latest)
.expect("balance will return Some if given BlockId::Latest. balance was given BlockId::Latest \
Therefore balance has returned Some; qed")
}
/// Get value of the storage at given position at the given block's state.
///
/// May not return None if given BlockId::Latest.
/// Returns None if and only if the block's root hash has been pruned from the DB.
fn storage_at(&self, address: &Address, position: &H256, id: BlockId) -> Option<H256>;
fn storage_at(&self, address: &Address, position: &H256, state: StateOrBlock) -> Option<H256>;
/// Get value of the storage at given position at the latest block's state.
fn latest_storage_at(&self, address: &Address, position: &H256) -> H256 {
self.storage_at(address, position, BlockId::Latest)
self.storage_at(address, position, BlockId::Latest.into())
.expect("storage_at will return Some if given BlockId::Latest. storage_at was given BlockId::Latest. \
Therefore storage_at has returned Some; qed")
}
@ -135,9 +256,6 @@ pub trait BlockChainClient : Sync + Send {
/// Get transaction with given hash.
fn transaction(&self, id: TransactionId) -> Option<LocalizedTransaction>;
/// Get the hash of block that contains the transaction, if any.
fn transaction_block(&self, id: TransactionId) -> Option<H256>;
/// Get uncle with given id.
fn uncle(&self, id: UncleId) -> Option<encoded::Header>;
@ -157,40 +275,18 @@ pub trait BlockChainClient : Sync + Send {
/// Get raw block receipts data by block header hash.
fn block_receipts(&self, hash: &H256) -> Option<Bytes>;
/// Import a block into the blockchain.
fn import_block(&self, bytes: Bytes) -> Result<H256, BlockImportError>;
/// Import a block with transaction receipts. Does no sealing and transaction validation.
fn import_block_with_receipts(&self, block_bytes: Bytes, receipts_bytes: Bytes) -> Result<H256, BlockImportError>;
/// Get block queue information.
fn queue_info(&self) -> BlockQueueInfo;
/// Clear block queue and abort all import activity.
fn clear_queue(&self);
/// Get blockchain information.
fn chain_info(&self) -> BlockChainInfo;
/// Get the registrar address, if it exists.
fn additional_params(&self) -> BTreeMap<String, String>;
/// Get the best block header.
fn best_block_header(&self) -> encoded::Header;
/// Returns logs matching given filter.
fn logs(&self, filter: Filter) -> Vec<LocalizedLogEntry>;
/// Makes a non-persistent transaction call.
fn call(&self, tx: &SignedTransaction, analytics: CallAnalytics, block: BlockId) -> Result<Executed, CallError>;
/// Makes multiple non-persistent but dependent transaction calls.
/// Returns a vector of successes or a failure if any of the transaction fails.
fn call_many(&self, txs: &[(SignedTransaction, CallAnalytics)], block: BlockId) -> Result<Vec<Executed>, CallError>;
/// Estimates how much gas will be necessary for a call.
fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result<U256, CallError>;
/// Replays a given transaction for inspection.
fn replay(&self, t: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError>;
@ -270,52 +366,64 @@ pub trait BlockChainClient : Sync + Send {
/// Returns information about pruning/data availability.
fn pruning_info(&self) -> PruningInfo;
/// 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>;
/// Get the address of the registry itself.
fn registrar_address(&self) -> Option<Address>;
/// Get the address of a particular blockchain service, if available.
fn registry_address(&self, name: String, block: BlockId) -> Option<Address>;
/// Get the EIP-86 transition block number.
fn eip86_transition(&self) -> u64;
}
/// Extended client interface used for mining
pub trait MiningBlockChainClient: BlockChainClient {
/// Provides `reopen_block` method
pub trait ReopenBlock {
/// Reopens an OpenBlock and updates uncles.
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock;
}
/// Provides `prepare_open_block` method
pub trait PrepareOpenBlock {
/// Returns OpenBlock prepared for closing.
fn prepare_open_block(&self,
author: Address,
gas_range_target: (U256, U256),
extra_data: Bytes
) -> OpenBlock;
}
/// Reopens an OpenBlock and updates uncles.
fn reopen_block(&self, block: ClosedBlock) -> OpenBlock;
/// Returns EvmFactory.
fn vm_factory(&self) -> &VmFactory;
/// Broadcast a block proposal.
fn broadcast_proposal_block(&self, block: SealedBlock);
/// Import sealed block. Skips all verifications.
fn import_sealed_block(&self, block: SealedBlock) -> ImportResult;
/// Provides methods used for sealing new state
pub trait BlockProducer: PrepareOpenBlock + ReopenBlock {}
/// Provides `latest_schedule` method
pub trait ScheduleInfo {
/// Returns latest schedule.
fn latest_schedule(&self) -> Schedule;
}
/// Returns base of this trait
fn as_block_chain_client(&self) -> &BlockChainClient;
///Provides `import_sealed_block` method
pub trait ImportSealedBlock {
/// Import sealed block. Skips all verifications.
fn import_sealed_block(&self, block: SealedBlock) -> ImportResult;
}
/// Provides `broadcast_proposal_block` method
pub trait BroadcastProposalBlock {
/// Broadcast a block proposal.
fn broadcast_proposal_block(&self, block: SealedBlock);
}
/// Provides methods to import sealed block and broadcast a block proposal
pub trait SealedBlockImporter: ImportSealedBlock + BroadcastProposalBlock {}
/// Extended client interface used for mining
pub trait MiningBlockChainClient: BlockChainClient + BlockProducer + ScheduleInfo + SealedBlockImporter {
/// Returns EvmFactory.
fn vm_factory(&self) -> &VmFactory;
}
/// Client facilities used by internally sealing Engines.
pub trait EngineClient: Sync + Send {
pub trait EngineClient: Sync + Send + ChainInfo {
/// Make a new block and seal it.
fn update_sealing(&self);
@ -332,9 +440,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;
/// Attempt to cast the engine client to a full client.
fn as_full_client(&self) -> Option<&BlockChainClient>;

View File

@ -781,6 +781,7 @@ mod tests {
use block::*;
use error::{Error, BlockError};
use header::Header;
use client::ChainInfo;
use miner::MinerService;
use tests::helpers::*;
use account_provider::AccountProvider;

View File

@ -145,7 +145,7 @@ mod tests {
use account_provider::AccountProvider;
use miner::MinerService;
use types::ids::BlockId;
use client::BlockChainClient;
use client::{BlockChainClient, ChainInfo, BlockInfo, CallContract};
use tests::helpers::generate_dummy_client_with_spec_and_accounts;
use super::super::ValidatorSet;
use super::ValidatorContract;

View File

@ -148,7 +148,7 @@ mod tests {
use std::collections::BTreeMap;
use hash::keccak;
use account_provider::AccountProvider;
use client::BlockChainClient;
use client::{BlockChainClient, ChainInfo, BlockInfo, ImportBlock};
use engines::EpochChange;
use engines::validator_set::ValidatorSet;
use ethkey::Secret;

View File

@ -456,7 +456,7 @@ mod tests {
use spec::Spec;
use account_provider::AccountProvider;
use transaction::{Transaction, Action};
use client::BlockChainClient;
use client::{ChainInfo, BlockInfo, ImportBlock};
use ethkey::Secret;
use miner::MinerService;
use tests::helpers::{generate_dummy_client_with_spec_and_accounts, generate_dummy_client_with_spec_and_data};

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use client::{EvmTestClient, BlockChainClient, Client, ClientConfig};
use client::{EvmTestClient, Client, ClientConfig, ChainInfo, ImportBlock};
use block::Block;
use spec::Genesis;
use ethjson;

View File

@ -22,7 +22,7 @@ use std::sync::Arc;
use block::{ExecutedBlock, IsBlock};
use builtin::Builtin;
use client::BlockChainClient;
use client::{BlockInfo, CallContract};
use error::Error;
use executive::Executive;
use header::{BlockNumber, Header};
@ -366,7 +366,7 @@ impl EthereumMachine {
/// Does verification of the transaction against the parent state.
// TODO: refine the bound here to be a "state provider" or similar as opposed
// to full client functionality.
pub fn verify_transaction(&self, t: &SignedTransaction, header: &Header, client: &BlockChainClient) -> Result<(), Error> {
pub fn verify_transaction<C: BlockInfo + CallContract>(&self, t: &SignedTransaction, header: &Header, client: &C) -> Result<(), Error> {
if let Some(ref filter) = self.tx_filter.as_ref() {
if !filter.transaction_allowed(header.parent_hash(), t, client) {
return Err(transaction::Error::NotAllowed.into())

View File

@ -36,7 +36,7 @@ use ethcore_miner::transaction_queue::{
TransactionOrigin,
};
use ethcore_miner::work_notify::{WorkPoster, NotifyWork};
use ethcore_miner::service_transaction_checker::ServiceTransactionChecker;
use miner::service_transaction_checker::ServiceTransactionChecker;
use miner::{MinerService, MinerStatus};
use price_info::fetch::Client as FetchClient;
use price_info::{Client as PriceInfoClient, PriceInfo};
@ -50,9 +50,11 @@ use transaction::{
Error as TransactionError,
};
use using_queue::{UsingQueue, GetAction};
use block::{ClosedBlock, IsBlock, Block};
use client::{MiningBlockChainClient, BlockId, TransactionId};
use client::{
AccountData, BlockChain, RegistryInfo, ScheduleInfo, CallContract, BlockProducer, SealedBlockImporter
};
use client::{BlockId, TransactionId, MiningBlockChainClient};
use executive::contract_address;
use header::{Header, BlockNumber};
use receipt::{Receipt, RichReceipt};
@ -386,7 +388,7 @@ impl Miner {
}
/// Prepares new block for sealing including top transactions from queue.
fn prepare_block(&self, chain: &MiningBlockChainClient) -> (ClosedBlock, Option<H256>) {
fn prepare_block<C: AccountData + BlockChain + BlockProducer + CallContract>(&self, chain: &C) -> (ClosedBlock, Option<H256>) {
trace_time!("prepare_block");
let chain_info = chain.chain_info();
let (transactions, mut open_block, original_work_hash) = {
@ -439,7 +441,7 @@ impl Miner {
let hash = tx.hash();
let start = Instant::now();
// Check whether transaction type is allowed for sender
let result = match self.engine.machine().verify_transaction(&tx, open_block.header(), chain.as_block_chain_client()) {
let result = match self.engine.machine().verify_transaction(&tx, open_block.header(), chain) {
Err(Error::Transaction(TransactionError::NotAllowed)) => {
Err(TransactionError::NotAllowed.into())
}
@ -567,7 +569,9 @@ impl Miner {
}
/// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal.
fn seal_and_import_block_internally(&self, chain: &MiningBlockChainClient, block: ClosedBlock) -> bool {
fn seal_and_import_block_internally<C>(&self, chain: &C, block: ClosedBlock) -> bool
where C: BlockChain + SealedBlockImporter
{
if !block.transactions().is_empty() || self.forced_sealing() || Instant::now() > *self.next_mandatory_reseal.read() {
trace!(target: "miner", "seal_block_internally: attempting internal seal.");
@ -647,7 +651,7 @@ impl Miner {
}
}
fn update_gas_limit(&self, client: &MiningBlockChainClient) {
fn update_gas_limit<C: BlockChain>(&self, client: &C) {
let gas_limit = client.best_block_header().gas_limit();
let mut queue = self.transaction_queue.write();
queue.set_gas_limit(gas_limit);
@ -658,7 +662,7 @@ impl Miner {
}
/// Returns true if we had to prepare new pending block.
fn prepare_work_sealing(&self, client: &MiningBlockChainClient) -> bool {
fn prepare_work_sealing<C: AccountData + BlockChain + BlockProducer + CallContract>(&self, client: &C) -> bool {
trace!(target: "miner", "prepare_work_sealing: entering");
let prepare_new = {
let mut sealing_work = self.sealing_work.lock();
@ -690,9 +694,9 @@ impl Miner {
prepare_new
}
fn add_transactions_to_queue(
fn add_transactions_to_queue<C: AccountData + BlockChain + CallContract + RegistryInfo + ScheduleInfo>(
&self,
client: &MiningBlockChainClient,
client: &C,
transactions: Vec<UnverifiedTransaction>,
default_origin: TransactionOrigin,
condition: Option<TransactionCondition>,
@ -718,7 +722,7 @@ impl Miner {
},
Ok(transaction) => {
// This check goes here because verify_transaction takes SignedTransaction parameter
self.engine.machine().verify_transaction(&transaction, &best_block_header, client.as_block_chain_client())?;
self.engine.machine().verify_transaction(&transaction, &best_block_header, client)?;
let origin = self.accounts.as_ref().and_then(|accounts| {
match accounts.has_account(transaction.sender()).unwrap_or(false) {
@ -774,8 +778,9 @@ impl Miner {
const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5;
impl MinerService for Miner {
type State = State<::state_db::StateDB>;
fn clear_and_reset(&self, chain: &MiningBlockChainClient) {
fn clear_and_reset<C: MiningBlockChainClient>(&self, chain: &C) {
self.transaction_queue.write().clear();
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
@ -891,16 +896,16 @@ impl MinerService for Miner {
self.gas_range_target.read().1
}
fn import_external_transactions(
fn import_external_transactions<C: MiningBlockChainClient>(
&self,
chain: &MiningBlockChainClient,
client: &C,
transactions: Vec<UnverifiedTransaction>
) -> Vec<Result<TransactionImportResult, Error>> {
trace!(target: "external_tx", "Importing external transactions");
let results = {
let mut transaction_queue = self.transaction_queue.write();
self.add_transactions_to_queue(
chain, transactions, TransactionOrigin::External, None, &mut transaction_queue
client, transactions, TransactionOrigin::External, None, &mut transaction_queue
)
};
@ -909,14 +914,14 @@ impl MinerService for Miner {
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.update_sealing(chain);
self.update_sealing(client);
}
results
}
fn import_own_transaction(
fn import_own_transaction<C: MiningBlockChainClient>(
&self,
chain: &MiningBlockChainClient,
chain: &C,
pending: PendingTransaction,
) -> Result<TransactionImportResult, Error> {
@ -1040,7 +1045,7 @@ impl MinerService for Miner {
}
}
fn remove_pending_transaction(&self, chain: &MiningBlockChainClient, hash: &H256) -> Option<PendingTransaction> {
fn remove_pending_transaction<C: AccountData>(&self, chain: &C, hash: &H256) -> Option<PendingTransaction> {
let mut queue = self.transaction_queue.write();
let tx = queue.find(hash);
if tx.is_some() {
@ -1110,7 +1115,10 @@ impl MinerService for Miner {
/// Update sealing if required.
/// Prepare the block and work if the Engine does not seal internally.
fn update_sealing(&self, chain: &MiningBlockChainClient) {
fn update_sealing<C>(&self, chain: &C)
where C: AccountData + BlockChain + RegistryInfo
+ CallContract + BlockProducer + SealedBlockImporter
{
trace!(target: "miner", "update_sealing");
const NO_NEW_CHAIN_WITH_FORKS: &str = "Your chain specification contains one or more hard forks which are required to be \
on by default. Please remove these forks and start your chain again.";
@ -1150,9 +1158,12 @@ impl MinerService for Miner {
self.sealing_work.lock().queue.is_in_use()
}
fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
fn map_sealing_work<C, F, T>(&self, client: &C, f: F) -> Option<T>
where C: AccountData + BlockChain + BlockProducer + CallContract,
F: FnOnce(&ClosedBlock) -> T
{
trace!(target: "miner", "map_sealing_work: entering");
self.prepare_work_sealing(chain);
self.prepare_work_sealing(client);
trace!(target: "miner", "map_sealing_work: sealing prepared");
let mut sealing_work = self.sealing_work.lock();
let ret = sealing_work.queue.use_last_ref();
@ -1160,7 +1171,7 @@ impl MinerService for Miner {
ret.map(f)
}
fn submit_seal(&self, chain: &MiningBlockChainClient, block_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> {
fn submit_seal<C: SealedBlockImporter>(&self, chain: &C, block_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> {
let result =
if let Some(b) = self.sealing_work.lock().queue.get_used_if(
if self.options.enable_resubmission {
@ -1188,7 +1199,10 @@ impl MinerService for Miner {
})
}
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256]) {
fn chain_new_blocks<C>(&self, chain: &C, imported: &[H256], _invalid: &[H256], enacted: &[H256], retracted: &[H256])
where C: AccountData + BlockChain + CallContract + RegistryInfo
+ BlockProducer + ScheduleInfo + SealedBlockImporter
{
trace!(target: "miner", "chain_new_blocks");
// 1. We ignore blocks that were `imported` unless resealing on new uncles is enabled.
@ -1234,6 +1248,18 @@ impl MinerService for Miner {
self.update_sealing(chain);
}
}
fn pending_state(&self, latest_block_number: BlockNumber) -> Option<Self::State> {
Miner::pending_state(self, latest_block_number)
}
fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option<Header> {
Miner::pending_block_header(self, latest_block_number)
}
fn pending_block(&self, latest_block_number: BlockNumber) -> Option<Block> {
Miner::pending_block(self, latest_block_number)
}
}
/// Action when service transaction is received
@ -1245,31 +1271,22 @@ enum ServiceTransactionAction {
}
impl ServiceTransactionAction {
pub fn check(&self, client: &MiningBlockChainClient, tx: &SignedTransaction) -> Result<bool, String> {
pub fn check<C: CallContract + RegistryInfo>(&self, client: &C, tx: &SignedTransaction) -> Result<bool, String>
{
match *self {
ServiceTransactionAction::Refuse => Err("configured to refuse service transactions".to_owned()),
ServiceTransactionAction::Check(ref checker) => checker.check(&client, tx),
ServiceTransactionAction::Check(ref checker) => checker.check(client, tx),
}
}
}
impl<'a> ::ethcore_miner::service_transaction_checker::ContractCaller for &'a MiningBlockChainClient {
fn registry_address(&self, name: &str) -> Option<Address> {
MiningBlockChainClient::registry_address(*self, name.into(), BlockId::Latest)
}
fn call_contract(&self, block: BlockId, address: Address, data: Vec<u8>) -> Result<Vec<u8>, String> {
MiningBlockChainClient::call_contract(*self, block, address, data)
}
}
struct TransactionDetailsProvider<'a> {
client: &'a MiningBlockChainClient,
struct TransactionDetailsProvider<'a, C: 'a> {
client: &'a C,
service_transaction_action: &'a ServiceTransactionAction,
}
impl<'a> TransactionDetailsProvider<'a> {
pub fn new(client: &'a MiningBlockChainClient, service_transaction_action: &'a ServiceTransactionAction) -> Self {
impl<'a, C> TransactionDetailsProvider<'a, C> {
pub fn new(client: &'a C, service_transaction_action: &'a ServiceTransactionAction) -> Self {
TransactionDetailsProvider {
client: client,
service_transaction_action: service_transaction_action,
@ -1277,7 +1294,9 @@ impl<'a> TransactionDetailsProvider<'a> {
}
}
impl<'a> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a> {
impl<'a, C> TransactionQueueDetailsProvider for TransactionDetailsProvider<'a, C>
where C: AccountData + CallContract + RegistryInfo + ScheduleInfo
{
fn fetch_account(&self, address: &Address) -> AccountDetails {
AccountDetails {
nonce: self.client.latest_nonce(address),
@ -1300,12 +1319,14 @@ mod tests {
use ethcore_miner::transaction_queue::PrioritizationStrategy;
use ethereum_types::U256;
use ethkey::{Generator, Random};
use client::{TestBlockChainClient, EachBlockWith, ChainInfo};
use hash::keccak;
use header::BlockNumber;
use rustc_hex::FromHex;
use transaction::Transaction;
use client::{BlockChainClient, TestBlockChainClient, EachBlockWith};
use spec::Spec;
use transaction::{SignedTransaction, Transaction, PendingTransaction, Action};
use miner::MinerService;
use tests::helpers::{generate_dummy_client, generate_dummy_client_with_spec_and_accounts};
#[test]

View File

@ -40,6 +40,7 @@
mod miner;
mod stratum;
mod service_transaction_checker;
pub use self::miner::{Miner, MinerOptions, Banning, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit};
pub use self::stratum::{Stratum, Error as StratumError, Options as StratumOptions};
@ -47,18 +48,24 @@ pub use self::stratum::{Stratum, Error as StratumError, Options as StratumOption
pub use ethcore_miner::local_transactions::Status as LocalTransactionStatus;
use std::collections::BTreeMap;
use ethereum_types::{H256, U256, Address};
use bytes::Bytes;
use block::ClosedBlock;
use client::{MiningBlockChainClient};
use block::{ClosedBlock, Block};
use bytes::Bytes;
use client::{
MiningBlockChainClient, CallContract, RegistryInfo, ScheduleInfo,
BlockChain, AccountData, BlockProducer, SealedBlockImporter
};
use error::{Error};
use header::BlockNumber;
use ethereum_types::{H256, U256, Address};
use header::{BlockNumber, Header};
use receipt::{RichReceipt, Receipt};
use transaction::{UnverifiedTransaction, PendingTransaction, ImportResult as TransactionImportResult};
use state::StateInfo;
/// Miner client API
pub trait MinerService : Send + Sync {
/// Type representing chain state
type State: StateInfo + 'static;
/// Returns miner's status.
fn status(&self) -> MinerStatus;
@ -107,42 +114,46 @@ pub trait MinerService : Send + Sync {
fn set_tx_gas_limit(&self, limit: U256);
/// Imports transactions to transaction queue.
fn import_external_transactions(&self, chain: &MiningBlockChainClient, transactions: Vec<UnverifiedTransaction>) ->
fn import_external_transactions<C: MiningBlockChainClient>(&self, client: &C, transactions: Vec<UnverifiedTransaction>) ->
Vec<Result<TransactionImportResult, Error>>;
/// Imports own (node owner) transaction to queue.
fn import_own_transaction(&self, chain: &MiningBlockChainClient, transaction: PendingTransaction) ->
fn import_own_transaction<C: MiningBlockChainClient>(&self, chain: &C, transaction: PendingTransaction) ->
Result<TransactionImportResult, Error>;
/// Returns hashes of transactions currently in pending
fn pending_transactions_hashes(&self, best_block: BlockNumber) -> Vec<H256>;
/// Removes all transactions from the queue and restart mining operation.
fn clear_and_reset(&self, chain: &MiningBlockChainClient);
fn clear_and_reset<C: MiningBlockChainClient>(&self, chain: &C);
/// Called when blocks are imported to chain, updates transactions queue.
fn chain_new_blocks(&self, chain: &MiningBlockChainClient, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256]);
fn chain_new_blocks<C>(&self, chain: &C, imported: &[H256], invalid: &[H256], enacted: &[H256], retracted: &[H256])
where C: AccountData + BlockChain + CallContract + RegistryInfo + BlockProducer + ScheduleInfo + SealedBlockImporter;
/// PoW chain - can produce work package
fn can_produce_work_package(&self) -> bool;
/// New chain head event. Restart mining operation.
fn update_sealing(&self, chain: &MiningBlockChainClient);
fn update_sealing<C>(&self, chain: &C)
where C: AccountData + BlockChain + RegistryInfo + CallContract + BlockProducer + SealedBlockImporter;
/// Submit `seal` as a valid solution for the header of `pow_hash`.
/// Will check the seal, but not actually insert the block into the chain.
fn submit_seal(&self, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error>;
fn submit_seal<C: SealedBlockImporter>(&self, chain: &C, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error>;
/// Get the sealing work package and if `Some`, apply some transform.
fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T>
where F: FnOnce(&ClosedBlock) -> T, Self: Sized;
fn map_sealing_work<C, F, T>(&self, client: &C, f: F) -> Option<T>
where C: AccountData + BlockChain + BlockProducer + CallContract,
F: FnOnce(&ClosedBlock) -> T,
Self: Sized;
/// Query pending transactions for hash.
fn transaction(&self, best_block: BlockNumber, hash: &H256) -> Option<PendingTransaction>;
/// Removes transaction from the queue.
/// NOTE: The transaction is not removed from pending block if mining.
fn remove_pending_transaction(&self, chain: &MiningBlockChainClient, hash: &H256) -> Option<PendingTransaction>;
fn remove_pending_transaction<C: AccountData>(&self, chain: &C, hash: &H256) -> Option<PendingTransaction>;
/// Get a list of all pending transactions in the queue.
fn pending_transactions(&self) -> Vec<PendingTransaction>;
@ -173,6 +184,15 @@ pub trait MinerService : Send + Sync {
/// Suggested gas limit.
fn sensible_gas_limit(&self) -> U256 { 21000.into() }
/// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing.
fn pending_state(&self, latest_block_number: BlockNumber) -> Option<Self::State>;
/// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing.
fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option<Header>;
/// Get `Some` `clone()` of the current pending block or `None` if we're not sealing.
fn pending_block(&self, latest_block_number: BlockNumber) -> Option<Block>;
}
/// Mining status

View File

@ -16,23 +16,14 @@
//! A service transactions contract checker.
use ethereum_types::Address;
use client::{RegistryInfo, CallContract};
use transaction::SignedTransaction;
use types::ids::BlockId;
use_contract!(service_transaction, "ServiceTransaction", "res/service_transaction.json");
use_contract!(service_transaction, "ServiceTransaction", "res/contracts/service_transaction.json");
const SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME: &'static str = "service_transaction_checker";
/// A contract calling interface.
pub trait ContractCaller {
/// Returns address of contract from the registry, given it's name
fn registry_address(&self, name: &str) -> Option<Address>;
/// Executes a contract call at given block.
fn call_contract(&self, BlockId, Address, Vec<u8>) -> Result<Vec<u8>, String>;
}
/// Service transactions checker.
#[derive(Default)]
pub struct ServiceTransactionChecker {
@ -41,10 +32,10 @@ pub struct ServiceTransactionChecker {
impl ServiceTransactionChecker {
/// Checks if service transaction can be appended to the transaction queue.
pub fn check(&self, client: &ContractCaller, tx: &SignedTransaction) -> Result<bool, String> {
pub fn check<C: CallContract + RegistryInfo>(&self, client: &C, tx: &SignedTransaction) -> Result<bool, String> {
assert!(tx.gas_price.is_zero());
let address = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME)
let address = client.registry_address(SERVICE_TRANSACTION_CONTRACT_REGISTRY_NAME.to_owned(), BlockId::Latest)
.ok_or_else(|| "contract is not configured")?;
trace!(target: "txqueue", "Checking service transaction checker contract from {}", address);

View File

@ -27,7 +27,7 @@ use super::{ManifestData, StateRebuilder, Rebuilder, RestorationStatus, Snapshot
use super::io::{SnapshotReader, LooseReader, SnapshotWriter, LooseWriter};
use blockchain::BlockChain;
use client::{BlockChainClient, Client};
use client::{Client, ChainInfo};
use engines::EthEngine;
use error::Error;
use ids::BlockId;

View File

@ -25,7 +25,7 @@ use hash::{KECCAK_NULL_RLP};
use account_db::AccountDBMut;
use basic_account::BasicAccount;
use blockchain::BlockChain;
use client::{BlockChainClient, Client};
use client::{Client, ChainInfo};
use engines::EthEngine;
use snapshot::{StateRebuilder};
use snapshot::io::{SnapshotReader, PackedWriter, PackedReader};

View File

@ -21,7 +21,7 @@ use std::sync::Arc;
use std::str::FromStr;
use account_provider::AccountProvider;
use client::{Client, BlockChainClient};
use client::{Client, BlockChainClient, ChainInfo};
use ethkey::Secret;
use snapshot::tests::helpers as snapshot_helpers;
use spec::Spec;

View File

@ -19,7 +19,7 @@
use std::sync::Arc;
use tempdir::TempDir;
use client::{BlockChainClient, Client};
use client::{Client, BlockInfo};
use ids::BlockId;
use snapshot::service::{Service, ServiceParams};
use snapshot::{self, ManifestData, SnapshotService};

View File

@ -17,7 +17,7 @@
//! Watcher for snapshot-related chain events.
use parking_lot::Mutex;
use client::{BlockChainClient, Client, ChainNotify};
use client::{BlockInfo, Client, ChainNotify};
use ids::BlockId;
use service::ClientIoMessage;

View File

@ -334,6 +334,28 @@ pub enum CleanupMode<'a> {
TrackTouched(&'a mut HashSet<Address>),
}
/// Provides subset of `State` methods to query state information
pub trait StateInfo {
/// Get the nonce of account `a`.
fn nonce(&self, a: &Address) -> trie::Result<U256>;
/// Get the balance of account `a`.
fn balance(&self, a: &Address) -> trie::Result<U256>;
/// Mutate storage of account `address` so that it is `value` for `key`.
fn storage_at(&self, address: &Address, key: &H256) -> trie::Result<H256>;
/// Get accounts' code.
fn code(&self, a: &Address) -> trie::Result<Option<Arc<Bytes>>>;
}
impl<B: Backend> StateInfo for State<B> {
fn nonce(&self, a: &Address) -> trie::Result<U256> { State::nonce(self, a) }
fn balance(&self, a: &Address) -> trie::Result<U256> { State::balance(self, a) }
fn storage_at(&self, address: &Address, key: &H256) -> trie::Result<H256> { State::storage_at(self, address, key) }
fn code(&self, address: &Address) -> trie::Result<Option<Arc<Bytes>>> { State::code(self, address) }
}
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
Therefore creating a SecTrieDB with this state's root will not fail.";

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! State database abstraction.
//! State database abstraction. For more info, see the doc for `StateDB`
use std::collections::{VecDeque, HashSet};
use std::sync::Arc;
@ -33,13 +33,17 @@ use bloom_journal::{Bloom, BloomJournal};
use db::COL_ACCOUNT_BLOOM;
use byteorder::{LittleEndian, ByteOrder};
/// Number of bytes allocated in the memory for accounts bloom.
/// Value used to initialize bloom bitmap size.
///
/// Bitmap size is the size in bytes (not bits) that will be allocated in memory.
pub const ACCOUNT_BLOOM_SPACE: usize = 1048576;
/// Estimated maximum number of accounts in memory bloom.
/// Value used to initialize bloom items count.
///
/// Items count is an estimation of the maximum number of items to store.
pub const DEFAULT_ACCOUNT_PRESET: usize = 1000000;
/// Database key represening number of account hashes.
/// Key for a value storing amount of hashes
pub const ACCOUNT_BLOOM_HASHCOUNT_KEY: &'static [u8] = b"account_hash_count";
const STATE_CACHE_BLOCKS: usize = 12;
@ -175,7 +179,7 @@ impl StateDB {
bloom
}
/// Commit bloom to a database transaction
/// Commit blooms journal to the database transaction
pub fn commit_bloom(batch: &mut DBTransaction, journal: BloomJournal) -> Result<(), UtilError> {
assert!(journal.hash_functions <= 255);
batch.put(COL_ACCOUNT_BLOOM, ACCOUNT_BLOOM_HASHCOUNT_KEY, &[journal.hash_functions as u8]);
@ -305,12 +309,12 @@ impl StateDB {
}
}
/// Returns immutable reference to underlying hashdb.
/// Conversion method to interpret self as `HashDB` reference
pub fn as_hashdb(&self) -> &HashDB {
self.db.as_hashdb()
}
/// Returns mutable reference to underlying hashdb.
/// Conversion method to interpret self as mutable `HashDB` reference
pub fn as_hashdb_mut(&mut self) -> &mut HashDB {
self.db.as_hashdb_mut()
}

View File

@ -18,7 +18,7 @@ use std::str::FromStr;
use std::sync::Arc;
use hash::keccak;
use io::IoChannel;
use client::{BlockChainClient, MiningBlockChainClient, Client, ClientConfig, BlockId};
use client::{BlockChainClient, Client, ClientConfig, BlockId, ChainInfo, BlockInfo, PrepareOpenBlock, ImportSealedBlock, ImportBlock};
use state::{self, State, CleanupMode};
use executive::{Executive, TransactOptions};
use ethereum;

View File

@ -19,7 +19,7 @@ use ethereum_types::{H256, U256};
use block::{OpenBlock, Drain};
use blockchain::{BlockChain, Config as BlockChainConfig};
use bytes::Bytes;
use client::{BlockChainClient, ChainNotify, Client, ClientConfig};
use client::{Client, ClientConfig, ChainInfo, ImportBlock, ChainNotify};
use ethereum::ethash::EthashParams;
use ethkey::KeyPair;
use evm::Factory as EvmFactory;

View File

@ -65,7 +65,12 @@ enum CacheId {
Bloom(H256),
}
/// Trace database.
/// Database to store transaction execution trace.
///
/// Whenever a transaction is executed by EVM it's execution trace is stored
/// in trace database. Each trace has information, which contracts have been
/// touched, which have been created during the execution of transaction, and
/// which calls failed.
pub struct TraceDB<T> where T: DatabaseExtras {
// cache
traces: RwLock<HashMap<H256, FlatBlockTraces>>,

View File

@ -19,7 +19,7 @@
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use ethereum_types::{H256, Address};
use client::{BlockChainClient, BlockId, ChainNotify};
use client::{BlockInfo, CallContract, BlockId, ChainNotify};
use bytes::Bytes;
use parking_lot::Mutex;
use spec::CommonParams;
@ -64,7 +64,7 @@ impl TransactionFilter {
}
/// Check if transaction is allowed at given block.
pub fn transaction_allowed(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &BlockChainClient) -> bool {
pub fn transaction_allowed<C: BlockInfo + CallContract>(&self, parent_hash: &H256, transaction: &SignedTransaction, client: &C) -> bool {
let mut cache = self.permission_cache.lock(); let len = cache.len();
let tx_type = match transaction.action {

View File

@ -16,6 +16,7 @@
//! Canonical verifier.
use client::{BlockInfo, CallContract};
use engines::EthEngine;
use error::Error;
use header::Header;
@ -25,13 +26,13 @@ use super::verification;
/// A canonial verifier -- this does full verification.
pub struct CanonVerifier;
impl Verifier for CanonVerifier {
impl<C: BlockInfo + CallContract> Verifier<C> for CanonVerifier {
fn verify_block_family(
&self,
header: &Header,
parent: &Header,
engine: &EthEngine,
do_full: Option<verification::FullFamilyParams>,
do_full: Option<verification::FullFamilyParams<C>>,
) -> Result<(), Error> {
verification::verify_block_family(header, parent, engine, do_full)
}

View File

@ -28,6 +28,8 @@ pub use self::canon_verifier::CanonVerifier;
pub use self::noop_verifier::NoopVerifier;
pub use self::queue::{BlockQueue, Config as QueueConfig, VerificationQueue, QueueInfo};
use client::{BlockInfo, CallContract};
/// Verifier type.
#[derive(Debug, PartialEq, Clone)]
pub enum VerifierType {
@ -47,7 +49,7 @@ impl Default for VerifierType {
}
/// Create a new verifier based on type.
pub fn new(v: VerifierType) -> Box<Verifier> {
pub fn new<C: BlockInfo + CallContract>(v: VerifierType) -> Box<Verifier<C>> {
match v {
VerifierType::Canon | VerifierType::CanonNoSeal => Box::new(CanonVerifier),
VerifierType::Noop => Box::new(NoopVerifier),

View File

@ -16,6 +16,7 @@
//! No-op verifier.
use client::{BlockInfo, CallContract};
use engines::EthEngine;
use error::Error;
use header::Header;
@ -25,13 +26,13 @@ use super::{verification, Verifier};
#[allow(dead_code)]
pub struct NoopVerifier;
impl Verifier for NoopVerifier {
impl<C: BlockInfo + CallContract> Verifier<C> for NoopVerifier {
fn verify_block_family(
&self,
_: &Header,
_t: &Header,
_: &EthEngine,
_: Option<verification::FullFamilyParams>
_: Option<verification::FullFamilyParams<C>>
) -> Result<(), Error> {
Ok(())
}

View File

@ -33,7 +33,7 @@ use triehash::ordered_trie_root;
use unexpected::{Mismatch, OutOfBounds};
use blockchain::*;
use client::BlockChainClient;
use client::{BlockInfo, CallContract};
use engines::EthEngine;
use error::{BlockError, Error};
use header::{BlockNumber, Header};
@ -109,24 +109,36 @@ pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &EthEngine,
})
}
/// Parameters for full verification of block family: block bytes, transactions, blockchain, and state access.
pub type FullFamilyParams<'a> = (&'a [u8], &'a [SignedTransaction], &'a BlockProvider, &'a BlockChainClient);
/// Parameters for full verification of block family
pub struct FullFamilyParams<'a, C: BlockInfo + CallContract + 'a> {
/// Serialized block bytes
pub block_bytes: &'a [u8],
/// Signed transactions
pub transactions: &'a [SignedTransaction],
/// Block provider to use during verification
pub block_provider: &'a BlockProvider,
/// Engine client to use during verification
pub client: &'a C,
}
/// Phase 3 verification. Check block information against parent and uncles.
pub fn verify_block_family(header: &Header, parent: &Header, engine: &EthEngine, do_full: Option<FullFamilyParams>) -> Result<(), Error> {
pub fn verify_block_family<C: BlockInfo + CallContract>(header: &Header, parent: &Header, engine: &EthEngine, do_full: Option<FullFamilyParams<C>>) -> Result<(), Error> {
// TODO: verify timestamp
verify_parent(&header, &parent, engine.params().gas_limit_bound_divisor)?;
engine.verify_block_family(&header, &parent)?;
let (bytes, txs, bc, client) = match do_full {
let params = match do_full {
Some(x) => x,
None => return Ok(()),
};
verify_uncles(header, bytes, bc, engine)?;
verify_uncles(header, params.block_bytes, params.block_provider, engine)?;
for transaction in txs {
engine.machine().verify_transaction(transaction, header, client)?;
for transaction in params.transactions {
engine.machine().verify_transaction(transaction, header, params.client)?;
}
Ok(())
@ -486,12 +498,12 @@ mod tests {
let parent = bc.block_header(header.parent_hash())
.ok_or(BlockError::UnknownParent(header.parent_hash().clone()))?;
let full_params: FullFamilyParams = (
bytes,
&transactions[..],
bc as &BlockProvider,
&client as &::client::BlockChainClient
);
let full_params = FullFamilyParams {
block_bytes: bytes,
transactions: &transactions[..],
block_provider: bc as &BlockProvider,
client: &client,
};
verify_block_family(&header, &parent, engine, Some(full_params))
}

View File

@ -16,20 +16,23 @@
//! A generic verifier trait.
use client::{BlockInfo, CallContract};
use engines::EthEngine;
use error::Error;
use header::Header;
use super::verification;
/// Should be used to verify blocks.
pub trait Verifier: Send + Sync {
pub trait Verifier<C>: Send + Sync
where C: BlockInfo + CallContract
{
/// Verify a block relative to its parent and uncles.
fn verify_block_family(
fn verify_block_family(
&self,
header: &Header,
parent: &Header,
engine: &EthEngine,
do_full: Option<verification::FullFamilyParams>
do_full: Option<verification::FullFamilyParams<C>>
) -> Result<(), Error>;
/// Do a final verification check for an enacted header vs its expected counterpart.

View File

@ -31,8 +31,6 @@ pub enum BlockId {
Earliest,
/// Latest mined block.
Latest,
/// Pending block.
Pending,
}
/// Uniquely identifies transaction.

View File

@ -31,10 +31,6 @@ extern crate parking_lot;
extern crate table;
extern crate transient_hashmap;
#[macro_use]
extern crate ethabi_derive;
#[macro_use]
extern crate ethabi_contract;
#[cfg(test)]
extern crate ethkey;
#[macro_use]
@ -45,6 +41,5 @@ extern crate rustc_hex;
pub mod banning_queue;
pub mod external;
pub mod local_transactions;
pub mod service_transaction_checker;
pub mod transaction_queue;
pub mod work_notify;

View File

@ -26,7 +26,7 @@ use ethereum_types::{U256, H256, Address};
use bytes::ToPretty;
use rlp::PayloadInfo;
use ethcore::service::ClientService;
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, BlockChainClient, BlockId};
use ethcore::client::{Mode, DatabaseCompactionProfile, VMType, BlockImportError, Nonce, Balance, BlockChainClient, BlockId, BlockInfo, ImportBlock};
use ethcore::db::NUM_COLUMNS;
use ethcore::error::ImportError;
use ethcore::miner::Miner;
@ -650,7 +650,7 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> {
}
for account in accounts.into_iter() {
let balance = client.balance(&account, at).unwrap_or_else(U256::zero);
let balance = client.balance(&account, at.into()).unwrap_or_else(U256::zero);
if cmd.min_balance.map_or(false, |m| balance < m) || cmd.max_balance.map_or(false, |m| balance > m) {
last = Some(account);
continue; //filtered out
@ -660,7 +660,7 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> {
out.write(b",").expect("Write error");
}
out.write_fmt(format_args!("\n\"0x{:x}\": {{\"balance\": \"{:x}\", \"nonce\": \"{:x}\"", account, balance, client.nonce(&account, at).unwrap_or_else(U256::zero))).expect("Write error");
let code = client.code(&account, at).unwrap_or(None).unwrap_or_else(Vec::new);
let code = client.code(&account, at.into()).unwrap_or(None).unwrap_or_else(Vec::new);
if !code.is_empty() {
out.write_fmt(format_args!(", \"code_hash\": \"0x{:x}\"", keccak(&code))).expect("Write error");
if cmd.code {
@ -683,7 +683,7 @@ fn execute_export_state(cmd: ExportState) -> Result<(), String> {
if last_storage.is_some() {
out.write(b",").expect("Write error");
}
out.write_fmt(format_args!("\n\t\"0x{:x}\": \"0x{:x}\"", key, client.storage_at(&account, &key, at).unwrap_or_else(Default::default))).expect("Write error");
out.write_fmt(format_args!("\n\t\"0x{:x}\": \"0x{:x}\"", key, client.storage_at(&account, &key, at.into()).unwrap_or_else(Default::default))).expect("Write error");
last_storage = Some(key);
}
}

View File

@ -20,7 +20,7 @@ use std::sync::Arc;
use bytes::Bytes;
use dir::default_data_path;
use dir::helpers::replace_home;
use ethcore::client::{Client, BlockChainClient, BlockId};
use ethcore::client::{Client, BlockChainClient, BlockId, CallContract};
use ethsync::LightSync;
use futures::{Future, future, IntoFuture};
use hash_fetch::fetch::Client as FetchClient;

View File

@ -22,7 +22,7 @@ use std::sync::{Arc};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::{Instant, Duration};
use ethcore::client::{BlockId, BlockChainClient, BlockChainInfo, BlockQueueInfo, ChainNotify, ClientReport, Client};
use ethcore::client::{BlockId, BlockChainClient, ChainInfo, BlockInfo, BlockChainInfo, BlockQueueInfo, ChainNotify, ClientReport, Client};
use ethcore::header::BlockNumber;
use ethcore::service::ClientIoMessage;
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};

View File

@ -60,6 +60,7 @@ node-health = { path = "../dapps/node-health" }
parity-reactor = { path = "../util/reactor" }
parity-updater = { path = "../updater" }
parity-version = { path = "../util/version" }
patricia-trie = { path = "../util/patricia_trie" }
rlp = { path = "../util/rlp" }
stats = { path = "../util/stats" }
vm = { path = "../ethcore/vm" }

View File

@ -68,6 +68,7 @@ extern crate rlp;
extern crate stats;
extern crate keccak_hash as hash;
extern crate hardware_wallet;
extern crate patricia_trie as trie;
#[macro_use]
extern crate log;

View File

@ -197,7 +197,19 @@ impl LightFetch {
let (sync, on_demand, client) = (self.sync.clone(), self.on_demand.clone(), self.client.clone());
let req: CallRequestHelper = req.into();
let id = num.unwrap_or_default().into();
// Note: Here we treat `Pending` as `Latest`.
// Since light clients don't produce pending blocks
// (they don't have state) we can safely fallback to `Latest`.
let id = match num.unwrap_or_default() {
BlockNumber::Num(n) => BlockId::Number(n),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => {
warn!("`Pending` is deprecated and may be removed in future versions. Falling back to `Latest`");
BlockId::Latest
}
};
let from = req.from.unwrap_or(Address::zero());
let nonce_fut = match req.nonce {
@ -308,7 +320,7 @@ impl LightFetch {
let best_number = self.client.chain_info().best_block_number;
let block_number = |id| match id {
BlockId::Earliest => Some(0),
BlockId::Latest | BlockId::Pending => Some(best_number),
BlockId::Latest => Some(best_number),
BlockId::Hash(h) => self.client.block_header(BlockId::Hash(h)).map(|hdr| hdr.number()),
BlockId::Number(x) => Some(x),
};

View File

@ -28,16 +28,17 @@ use parking_lot::Mutex;
use ethash::SeedHashCompute;
use ethcore::account_provider::{AccountProvider, DappId};
use ethcore::block::IsBlock;
use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId};
use ethcore::client::{MiningBlockChainClient, BlockId, TransactionId, UncleId, StateOrBlock, StateClient, StateInfo, Call, EngineInfo};
use ethcore::ethereum::Ethash;
use ethcore::filter::Filter as EthcoreFilter;
use ethcore::header::{Header as BlockHeader, BlockNumber as EthBlockNumber};
use ethcore::header::{BlockNumber as EthBlockNumber, Seal};
use ethcore::log_entry::LogEntry;
use ethcore::miner::MinerService;
use ethcore::snapshot::SnapshotService;
use ethcore::encoded;
use ethsync::{SyncProvider};
use miner::external::ExternalMinerService;
use transaction::SignedTransaction;
use transaction::{SignedTransaction, LocalizedTransaction};
use jsonrpc_core::{BoxFuture, Result};
use jsonrpc_core::futures::future;
@ -51,11 +52,11 @@ use v1::traits::Eth;
use v1::types::{
RichBlock, Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo,
Transaction, CallRequest, Index, Filter, Log, Receipt, Work,
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256,
H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256, block_number_to_id,
};
use v1::metadata::Metadata;
const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed";
const EXTRA_INFO_PROOF: &'static str = "Object exists in blockchain (fetched earlier), extra_info is always available if object exists; qed";
/// Eth RPC options
pub struct EthClientOptions {
@ -109,11 +110,43 @@ pub struct EthClient<C, SN: ?Sized, S: ?Sized, M, EM> where
eip86_transition: u64,
}
impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
C: MiningBlockChainClient,
enum BlockNumberOrId {
Number(BlockNumber),
Id(BlockId),
}
impl From<BlockId> for BlockNumberOrId {
fn from(value: BlockId) -> BlockNumberOrId {
BlockNumberOrId::Id(value)
}
}
impl From<BlockNumber> for BlockNumberOrId {
fn from(value: BlockNumber) -> BlockNumberOrId {
BlockNumberOrId::Number(value)
}
}
enum PendingOrBlock {
Block(BlockId),
Pending,
}
struct PendingUncleId {
id: PendingOrBlock,
position: usize,
}
enum PendingTransactionId {
Hash(H256),
Location(PendingOrBlock, usize)
}
impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S, M, EM> where
C: MiningBlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo,
SN: SnapshotService,
S: SyncProvider,
M: MinerService,
M: MinerService<State=T>,
EM: ExternalMinerService {
/// Creates new EthClient.
@ -145,9 +178,46 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
unwrap_provider(&self.accounts)
}
fn block(&self, id: BlockId, include_txs: bool) -> Result<Option<RichBlock>> {
fn rich_block(&self, id: BlockNumberOrId, include_txs: bool) -> Result<Option<RichBlock>> {
let client = &self.client;
match (client.block(id.clone()), client.block_total_difficulty(id)) {
let client_query = |id| (client.block(id), client.block_total_difficulty(id), client.block_extra_info(id));
let (block, difficulty, extra) = match id {
BlockNumberOrId::Number(BlockNumber::Pending) => {
let info = self.client.chain_info();
let pending_block = self.miner.pending_block(info.best_block_number);
let difficulty = {
let latest_difficulty = self.client.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed");
let pending_difficulty = self.miner.pending_block_header(info.best_block_number).map(|header| *header.difficulty());
if let Some(difficulty) = pending_difficulty {
difficulty + latest_difficulty
} else {
latest_difficulty
}
};
let extra = pending_block.as_ref().map(|b| self.client.engine().extra_info(&b.header));
(pending_block.map(|b| encoded::Block::new(b.rlp_bytes(Seal::Without))), Some(difficulty), extra)
},
BlockNumberOrId::Number(num) => {
let id = match num {
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Num(n) => BlockId::Number(n),
BlockNumber::Pending => unreachable!(), // Already covered
};
client_query(id)
},
BlockNumberOrId::Id(id) => client_query(id),
};
match (block, difficulty) {
(Some(block), Some(total_difficulty)) => {
let view = block.header_view();
Ok(Some(RichBlock {
@ -176,29 +246,109 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
},
extra_data: Bytes::new(view.extra_data()),
},
extra_info: client.block_extra_info(id.clone()).expect(EXTRA_INFO_PROOF),
extra_info: extra.expect(EXTRA_INFO_PROOF),
}))
},
_ => Ok(None)
}
}
fn transaction(&self, id: TransactionId) -> Result<Option<Transaction>> {
match self.client.transaction(id) {
fn transaction(&self, id: PendingTransactionId) -> Result<Option<Transaction>> {
let client_transaction = |id| match self.client.transaction(id) {
Some(t) => Ok(Some(Transaction::from_localized(t, self.eip86_transition))),
None => Ok(None),
};
match id {
PendingTransactionId::Hash(hash) => client_transaction(TransactionId::Hash(hash)),
PendingTransactionId::Location(PendingOrBlock::Block(block), index) => {
client_transaction(TransactionId::Location(block, index))
},
PendingTransactionId::Location(PendingOrBlock::Pending, index) => {
let info = self.client.chain_info();
let pending_block = match self.miner.pending_block(info.best_block_number) {
Some(block) => block,
None => return Ok(None),
};
// Implementation stolen from `extract_transaction_at_index`
let transaction = pending_block.transactions.get(index)
// Verify if transaction signature is correct.
.and_then(|tx| SignedTransaction::new(tx.clone()).ok())
.map(|signed_tx| {
let (signed, sender, _) = signed_tx.deconstruct();
let block_hash = pending_block.header.hash();
let block_number = pending_block.header.number();
let transaction_index = index;
let cached_sender = Some(sender);
LocalizedTransaction {
signed,
block_number,
block_hash,
transaction_index,
cached_sender,
}
})
.map(|tx| Transaction::from_localized(tx, self.eip86_transition));
Ok(transaction)
}
}
}
fn uncle(&self, id: UncleId) -> Result<Option<RichBlock>> {
fn uncle(&self, id: PendingUncleId) -> Result<Option<RichBlock>> {
let client = &self.client;
let uncle: BlockHeader = match client.uncle(id) {
Some(hdr) => hdr.decode(),
None => { return Ok(None); }
};
let parent_difficulty = match client.block_total_difficulty(BlockId::Hash(uncle.parent_hash().clone())) {
Some(difficulty) => difficulty,
None => { return Ok(None); }
let (uncle, parent_difficulty, extra) = match id {
PendingUncleId { id: PendingOrBlock::Pending, position } => {
let info = self.client.chain_info();
let pending_block = match self.miner.pending_block(info.best_block_number) {
Some(block) => block,
None => return Ok(None),
};
let uncle = match pending_block.uncles.get(position) {
Some(uncle) => uncle.clone(),
None => return Ok(None),
};
let difficulty = {
let latest_difficulty = self.client.block_total_difficulty(BlockId::Latest).expect("blocks in chain have details; qed");
let pending_difficulty = self.miner.pending_block_header(info.best_block_number).map(|header| *header.difficulty());
if let Some(difficulty) = pending_difficulty {
difficulty + latest_difficulty
} else {
latest_difficulty
}
};
let extra = self.client.engine().extra_info(&pending_block.header);
(uncle, difficulty, extra)
},
PendingUncleId { id: PendingOrBlock::Block(block_id), position } => {
let uncle_id = UncleId { block: block_id, position };
let uncle = match client.uncle(uncle_id) {
Some(hdr) => hdr.decode(),
None => { return Ok(None); }
};
let parent_difficulty = match client.block_total_difficulty(BlockId::Hash(uncle.parent_hash().clone())) {
Some(difficulty) => difficulty,
None => { return Ok(None); }
};
let extra = client.uncle_extra_info(uncle_id).expect(EXTRA_INFO_PROOF);
(uncle, parent_difficulty, extra)
}
};
let size = client.block(BlockId::Hash(uncle.hash()))
@ -229,7 +379,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
uncles: vec![],
transactions: BlockTransactions::Hashes(vec![]),
},
extra_info: client.uncle_extra_info(id).expect(EXTRA_INFO_PROOF),
extra_info: extra,
};
Ok(Some(block))
}
@ -241,6 +391,24 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
.and_then(|_| store.dapp_addresses(dapp))
.map_err(|e| errors::account("Could not fetch accounts.", e))
}
fn get_state(&self, number: BlockNumber) -> StateOrBlock {
match number {
BlockNumber::Num(num) => BlockId::Number(num).into(),
BlockNumber::Earliest => BlockId::Earliest.into(),
BlockNumber::Latest => BlockId::Latest.into(),
BlockNumber::Pending => {
let info = self.client.chain_info();
self.miner
.pending_state(info.best_block_number)
.map(|s| Box::new(s) as Box<StateInfo>)
.unwrap_or(Box::new(self.client.latest_state()) as Box<StateInfo>)
.into()
}
}
}
}
pub fn pending_logs<M>(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFilter) -> Vec<Log> where M: MinerService {
@ -265,20 +433,27 @@ pub fn pending_logs<M>(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFi
fn check_known<C>(client: &C, number: BlockNumber) -> Result<()> where C: MiningBlockChainClient {
use ethcore::block_status::BlockStatus;
match client.block_status(number.into()) {
let id = match number {
BlockNumber::Pending => return Ok(()),
BlockNumber::Num(n) => BlockId::Number(n),
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Earliest => BlockId::Earliest,
};
match client.block_status(id) {
BlockStatus::InChain => Ok(()),
BlockStatus::Pending => Ok(()),
_ => Err(errors::unknown_block()),
}
}
const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6.
impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
C: MiningBlockChainClient + 'static,
impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<C, SN, S, M, EM> where
C: MiningBlockChainClient + StateClient<State=T> + Call<State=T> + EngineInfo + 'static,
SN: SnapshotService + 'static,
S: SyncProvider + 'static,
M: MinerService + 'static,
M: MinerService<State=T> + 'static,
EM: ExternalMinerService + 'static,
{
type Metadata = Metadata;
@ -357,10 +532,10 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
fn balance(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> {
let address = address.into();
let id = num.unwrap_or_default();
let num = num.unwrap_or_default();
try_bf!(check_known(&*self.client, id.clone()));
let res = match self.client.balance(&address, id.into()) {
try_bf!(check_known(&*self.client, num.clone()));
let res = match self.client.balance(&address, self.get_state(num)) {
Some(balance) => Ok(balance.into()),
None => Err(errors::state_pruned()),
};
@ -372,10 +547,10 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
let address: Address = RpcH160::into(address);
let position: U256 = RpcU256::into(pos);
let id = num.unwrap_or_default();
let num = num.unwrap_or_default();
try_bf!(check_known(&*self.client, id.clone()));
let res = match self.client.storage_at(&address, &H256::from(position), id.into()) {
try_bf!(check_known(&*self.client, num.clone()));
let res = match self.client.storage_at(&address, &H256::from(position), self.get_state(num)) {
Some(s) => Ok(s.into()),
None => Err(errors::state_pruned()),
};
@ -390,15 +565,33 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
BlockNumber::Pending if self.options.pending_nonce_from_queue => {
let nonce = self.miner.last_nonce(&address)
.map(|n| n + 1.into())
.or_else(|| self.client.nonce(&address, BlockNumber::Pending.into()));
.or_else(|| self.client.nonce(&address, BlockId::Latest));
match nonce {
Some(nonce) => Ok(nonce.into()),
None => Err(errors::database("latest nonce missing"))
}
}
id => {
try_bf!(check_known(&*self.client, id.clone()));
match self.client.nonce(&address, id.into()) {
},
BlockNumber::Pending => {
let info = self.client.chain_info();
let nonce = self.miner
.pending_state(info.best_block_number)
.and_then(|s| s.nonce(&address).ok())
.or_else(|| {
warn!("Fallback to `BlockId::Latest`");
self.client.nonce(&address, BlockId::Latest)
});
match nonce {
Some(nonce) => Ok(nonce.into()),
None => Err(errors::database("latest nonce missing"))
}
},
number => {
try_bf!(check_known(&*self.client, number.clone()));
match self.client.nonce(&address, block_number_to_id(number)) {
Some(nonce) => Ok(nonce.into()),
None => Err(errors::state_pruned()),
}
@ -419,7 +612,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
self.miner.status().transactions_in_pending_block.into()
),
_ =>
self.client.block(num.into())
self.client.block(block_number_to_id(num))
.map(|block| block.transactions_count().into())
}))
}
@ -432,7 +625,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> {
Box::new(future::ok(match num {
BlockNumber::Pending => Some(0.into()),
_ => self.client.block(num.into())
_ => self.client.block(block_number_to_id(num))
.map(|block| block.uncles_count().into()
),
}))
@ -441,10 +634,10 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<Bytes> {
let address: Address = RpcH160::into(address);
let id = num.unwrap_or_default();
try_bf!(check_known(&*self.client, id.clone()));
let num = num.unwrap_or_default();
try_bf!(check_known(&*self.client, num.clone()));
let res = match self.client.code(&address, id.into()) {
let res = match self.client.code(&address, self.get_state(num)) {
Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)),
None => Err(errors::state_pruned()),
};
@ -453,17 +646,17 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
Box::new(future::done(self.block(BlockId::Hash(hash.into()), include_txs)))
Box::new(future::done(self.rich_block(BlockId::Hash(hash.into()).into(), include_txs)))
}
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
Box::new(future::done(self.block(num.into(), include_txs)))
Box::new(future::done(self.rich_block(num.into(), include_txs)))
}
fn transaction_by_hash(&self, hash: RpcH256) -> BoxFuture<Option<Transaction>> {
let hash: H256 = hash.into();
let block_number = self.client.chain_info().best_block_number;
let tx = try_bf!(self.transaction(TransactionId::Hash(hash))).or_else(|| {
let tx = try_bf!(self.transaction(PendingTransactionId::Hash(hash))).or_else(|| {
self.miner.transaction(block_number, &hash)
.map(|t| Transaction::from_pending(t, block_number, self.eip86_transition))
});
@ -472,15 +665,20 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn transaction_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> BoxFuture<Option<Transaction>> {
Box::new(future::done(
self.transaction(TransactionId::Location(BlockId::Hash(hash.into()), index.value()))
))
let id = PendingTransactionId::Location(PendingOrBlock::Block(BlockId::Hash(hash.into())), index.value());
Box::new(future::done(self.transaction(id)))
}
fn transaction_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<Transaction>> {
Box::new(future::done(
self.transaction(TransactionId::Location(num.into(), index.value()))
))
let block_id = match num {
BlockNumber::Latest => PendingOrBlock::Block(BlockId::Latest),
BlockNumber::Earliest => PendingOrBlock::Block(BlockId::Earliest),
BlockNumber::Num(num) => PendingOrBlock::Block(BlockId::Number(num)),
BlockNumber::Pending => PendingOrBlock::Pending,
};
let transaction_id = PendingTransactionId::Location(block_id, index.value());
Box::new(future::done(self.transaction(transaction_id)))
}
fn transaction_receipt(&self, hash: RpcH256) -> BoxFuture<Option<Receipt>> {
@ -497,17 +695,22 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn uncle_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> BoxFuture<Option<RichBlock>> {
Box::new(future::done(self.uncle(UncleId {
block: BlockId::Hash(hash.into()),
Box::new(future::done(self.uncle(PendingUncleId {
id: PendingOrBlock::Block(BlockId::Hash(hash.into())),
position: index.value()
})))
}
fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<RichBlock>> {
Box::new(future::done(self.uncle(UncleId {
block: num.into(),
position: index.value()
})))
let id = match num {
BlockNumber::Latest => PendingUncleId { id: PendingOrBlock::Block(BlockId::Latest), position: index.value() },
BlockNumber::Earliest => PendingUncleId { id: PendingOrBlock::Block(BlockId::Earliest), position: index.value() },
BlockNumber::Num(num) => PendingUncleId { id: PendingOrBlock::Block(BlockId::Number(num)), position: index.value() },
BlockNumber::Pending => PendingUncleId { id: PendingOrBlock::Pending, position: index.value() },
};
Box::new(future::done(self.uncle(id)))
}
fn compilers(&self) -> Result<Vec<String>> {
@ -630,7 +833,28 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
let signed = try_bf!(fake_sign::sign_call(request, meta.is_dapp()));
let num = num.unwrap_or_default();
let result = self.client.call(&signed, Default::default(), num.into());
let (mut state, header) = if num == BlockNumber::Pending {
let info = self.client.chain_info();
let state = try_bf!(self.miner.pending_state(info.best_block_number).ok_or(errors::state_pruned()));
let header = try_bf!(self.miner.pending_block_header(info.best_block_number).ok_or(errors::state_pruned()));
(state, header)
} else {
let id = match num {
BlockNumber::Num(num) => BlockId::Number(num),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => unreachable!(), // Already covered
};
let state = try_bf!(self.client.state_at(id).ok_or(errors::state_pruned()));
let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned()));
(state, header.decode())
};
let result = self.client.call(&signed, Default::default(), &mut state, &header);
Box::new(future::done(result
.map(|b| b.output.into())
@ -641,7 +865,29 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
fn estimate_gas(&self, meta: Self::Metadata, request: CallRequest, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> {
let request = CallRequest::into(request);
let signed = try_bf!(fake_sign::sign_call(request, meta.is_dapp()));
Box::new(future::done(self.client.estimate_gas(&signed, num.unwrap_or_default().into())
let num = num.unwrap_or_default();
let (state, header) = if num == BlockNumber::Pending {
let info = self.client.chain_info();
let state = try_bf!(self.miner.pending_state(info.best_block_number).ok_or(errors::state_pruned()));
let header = try_bf!(self.miner.pending_block_header(info.best_block_number).ok_or(errors::state_pruned()));
(state, header)
} else {
let id = match num {
BlockNumber::Num(num) => BlockId::Number(num),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => unreachable!(), // Already covered
};
let state = try_bf!(self.client.state_at(id).ok_or(errors::state_pruned()));
let header = try_bf!(self.client.block_header(id).ok_or(errors::state_pruned()));
(state, header.decode())
};
Box::new(future::done(self.client.estimate_gas(&signed, &state, &header)
.map(Into::into)
.map_err(errors::call)
))

View File

@ -65,6 +65,23 @@ pub struct EthClient<T> {
gas_price_percentile: usize,
}
impl<T> EthClient<T> {
fn num_to_id(num: BlockNumber) -> BlockId {
// Note: Here we treat `Pending` as `Latest`.
// Since light clients don't produce pending blocks
// (they don't have state) we can safely fallback to `Latest`.
match num {
BlockNumber::Num(n) => BlockId::Number(n),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => {
warn!("`Pending` is deprecated and may be removed in future versions. Falling back to `Latest`");
BlockId::Latest
}
}
}
}
impl<T> Clone for EthClient<T> {
fn clone(&self) -> Self {
// each instance should have its own poll manager.
@ -264,7 +281,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
}
fn balance(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> {
Box::new(self.fetcher().account(address.into(), num.unwrap_or_default().into())
Box::new(self.fetcher().account(address.into(), Self::num_to_id(num.unwrap_or_default()))
.map(|acc| acc.map_or(0.into(), |a| a.balance).into()))
}
@ -277,11 +294,11 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
}
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> BoxFuture<Option<RichBlock>> {
Box::new(self.rich_block(num.into(), include_txs).map(Some))
Box::new(self.rich_block(Self::num_to_id(num), include_txs).map(Some))
}
fn transaction_count(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<RpcU256> {
Box::new(self.fetcher().account(address.into(), num.unwrap_or_default().into())
Box::new(self.fetcher().account(address.into(), Self::num_to_id(num.unwrap_or_default()))
.map(|acc| acc.map_or(0.into(), |a| a.nonce).into()))
}
@ -304,7 +321,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
fn block_transaction_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> {
let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone());
Box::new(self.fetcher().header(num.into()).and_then(move |hdr| {
Box::new(self.fetcher().header(Self::num_to_id(num)).and_then(move |hdr| {
if hdr.transactions_root() == KECCAK_NULL_RLP {
Either::A(future::ok(Some(U256::from(0).into())))
} else {
@ -336,7 +353,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
fn block_uncles_count_by_number(&self, num: BlockNumber) -> BoxFuture<Option<RpcU256>> {
let (sync, on_demand) = (self.sync.clone(), self.on_demand.clone());
Box::new(self.fetcher().header(num.into()).and_then(move |hdr| {
Box::new(self.fetcher().header(Self::num_to_id(num)).and_then(move |hdr| {
if hdr.uncles_hash() == KECCAK_EMPTY_LIST_RLP {
Either::B(future::ok(Some(U256::from(0).into())))
} else {
@ -350,7 +367,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
}
fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> BoxFuture<Bytes> {
Box::new(self.fetcher().code(address.into(), num.unwrap_or_default().into()).map(Into::into))
Box::new(self.fetcher().code(address.into(), Self::num_to_id(num.unwrap_or_default())).map(Into::into))
}
fn send_raw_transaction(&self, raw: Bytes) -> Result<RpcH256> {
@ -422,7 +439,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
fn transaction_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture<Option<Transaction>> {
let eip86 = self.client.eip86_transition();
Box::new(self.fetcher().block(num.into()).map(move |block| {
Box::new(self.fetcher().block(Self::num_to_id(num)).map(move |block| {
light_fetch::extract_transaction_at_index(block, idx.value(), eip86)
}))
}
@ -467,7 +484,7 @@ impl<T: LightChainClient + 'static> Eth for EthClient<T> {
fn uncle_by_block_number_and_index(&self, num: BlockNumber, idx: Index) -> BoxFuture<Option<RichBlock>> {
let client = self.client.clone();
Box::new(self.fetcher().block(num.into()).map(move |block| {
Box::new(self.fetcher().block(Self::num_to_id(num)).map(move |block| {
extract_uncle_at_index(block, idx, client)
}))
}

View File

@ -27,6 +27,7 @@ use ethsync::LightSyncProvider;
use ethcore::account_provider::AccountProvider;
use ethcore_logger::RotatingLogger;
use node_health::{NodeHealth, Health};
use ethcore::ids::BlockId;
use light::client::LightChainClient;
@ -405,7 +406,16 @@ impl Parity for ParityClient {
}
};
Box::new(self.fetcher().header(number.unwrap_or_default().into()).map(from_encoded))
// Note: Here we treat `Pending` as `Latest`.
// Since light clients don't produce pending blocks
// (they don't have state) we can safely fallback to `Latest`.
let id = match number.unwrap_or_default() {
BlockNumber::Num(n) => BlockId::Number(n),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest,
};
Box::new(self.fetcher().header(id).map(from_encoded))
}
fn ipfs_cid(&self, content: Bytes) -> Result<String> {

View File

@ -27,10 +27,11 @@ use ethkey::{Brain, Generator};
use ethstore::random_phrase;
use ethsync::{SyncProvider, ManageNetwork};
use ethcore::account_provider::AccountProvider;
use ethcore::client::{MiningBlockChainClient};
use ethcore::client::{MiningBlockChainClient, StateClient, Call};
use ethcore::ids::BlockId;
use ethcore::miner::MinerService;
use ethcore::mode::Mode;
use ethcore::state::StateInfo;
use ethcore_logger::RotatingLogger;
use node_health::{NodeHealth, Health};
use updater::{Service as UpdateService};
@ -48,7 +49,8 @@ use v1::types::{
TransactionStats, LocalTransactionStatus,
BlockNumber, ConsensusCapability, VersionInfo,
OperationsInfo, DappId, ChainStatus,
AccountInfo, HwAccountInfo, RichHeader
AccountInfo, HwAccountInfo, RichHeader,
block_number_to_id
};
use Host;
@ -112,9 +114,10 @@ impl<C, M, U> ParityClient<C, M, U> where
}
}
impl<C, M, U> Parity for ParityClient<C, M, U> where
C: MiningBlockChainClient + 'static,
M: MinerService + 'static,
impl<C, M, U, S> Parity for ParityClient<C, M, U> where
S: StateInfo + 'static,
C: MiningBlockChainClient + StateClient<State=S> + Call<State=S> + 'static,
M: MinerService<State=S> + 'static,
U: UpdateService + 'static,
{
type Metadata = Metadata;
@ -275,14 +278,32 @@ impl<C, M, U> Parity for ParityClient<C, M, U> where
}
fn list_accounts(&self, count: u64, after: Option<H160>, block_number: Trailing<BlockNumber>) -> Result<Option<Vec<H160>>> {
let number = match block_number.unwrap_or_default() {
BlockNumber::Pending => {
warn!("BlockNumber::Pending is unsupported");
return Ok(None);
},
num => block_number_to_id(num)
};
Ok(self.client
.list_accounts(block_number.unwrap_or_default().into(), after.map(Into::into).as_ref(), count)
.list_accounts(number, after.map(Into::into).as_ref(), count)
.map(|a| a.into_iter().map(Into::into).collect()))
}
fn list_storage_keys(&self, address: H160, count: u64, after: Option<H256>, block_number: Trailing<BlockNumber>) -> Result<Option<Vec<H256>>> {
let number = match block_number.unwrap_or_default() {
BlockNumber::Pending => {
warn!("BlockNumber::Pending is unsupported");
return Ok(None);
},
num => block_number_to_id(num)
};
Ok(self.client
.list_storage(block_number.unwrap_or_default().into(), &address.into(), after.map(Into::into).as_ref(), count)
.list_storage(number, &address.into(), after.map(Into::into).as_ref(), count)
.map(|a| a.into_iter().map(Into::into).collect()))
}
@ -396,17 +417,31 @@ impl<C, M, U> Parity for ParityClient<C, M, U> where
}
fn block_header(&self, number: Trailing<BlockNumber>) -> BoxFuture<RichHeader> {
const EXTRA_INFO_PROOF: &'static str = "Object exists in in blockchain (fetched earlier), extra_info is always available if object exists; qed";
const EXTRA_INFO_PROOF: &str = "Object exists in blockchain (fetched earlier), extra_info is always available if object exists; qed";
let number = number.unwrap_or_default();
let id: BlockId = number.unwrap_or_default().into();
let encoded = match self.client.block_header(id.clone()) {
Some(encoded) => encoded,
None => return Box::new(future::err(errors::unknown_block())),
let (header, extra) = if number == BlockNumber::Pending {
let info = self.client.chain_info();
let header = try_bf!(self.miner.pending_block_header(info.best_block_number).ok_or(errors::unknown_block()));
(header.encoded(), None)
} else {
let id = match number {
BlockNumber::Num(num) => BlockId::Number(num),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => unreachable!(), // Already covered
};
let header = try_bf!(self.client.block_header(id.clone()).ok_or(errors::unknown_block()));
let info = self.client.block_extra_info(id).expect(EXTRA_INFO_PROOF);
(header, Some(info))
};
Box::new(future::ok(RichHeader {
inner: encoded.into(),
extra_info: self.client.block_extra_info(id).expect(EXTRA_INFO_PROOF),
inner: header.into(),
extra_info: extra.unwrap_or_default(),
}))
}
@ -414,7 +449,7 @@ impl<C, M, U> Parity for ParityClient<C, M, U> where
ipfs::cid(content)
}
fn call(&self, meta: Self::Metadata, requests: Vec<CallRequest>, block: Trailing<BlockNumber>) -> Result<Vec<Bytes>> {
fn call(&self, meta: Self::Metadata, requests: Vec<CallRequest>, num: Trailing<BlockNumber>) -> Result<Vec<Bytes>> {
let requests = requests
.into_iter()
.map(|request| Ok((
@ -423,9 +458,29 @@ impl<C, M, U> Parity for ParityClient<C, M, U> where
)))
.collect::<Result<Vec<_>>>()?;
let block = block.unwrap_or_default();
let num = num.unwrap_or_default();
self.client.call_many(&requests, block.into())
let (mut state, header) = if num == BlockNumber::Pending {
let info = self.client.chain_info();
let state = self.miner.pending_state(info.best_block_number).ok_or(errors::state_pruned())?;
let header = self.miner.pending_block_header(info.best_block_number).ok_or(errors::state_pruned())?;
(state, header)
} else {
let id = match num {
BlockNumber::Num(num) => BlockId::Number(num),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => unreachable!(), // Already covered
};
let state = self.client.state_at(id).ok_or(errors::state_pruned())?;
let header = self.client.block_header(id).ok_or(errors::state_pruned())?;
(state, header.decode())
};
self.client.call_many(&requests, &mut state, &header)
.map(|res| res.into_iter().map(|res| res.output.into()).collect())
.map_err(errors::call)
}

View File

@ -18,7 +18,7 @@
use std::sync::Arc;
use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId};
use ethcore::client::{MiningBlockChainClient, CallAnalytics, TransactionId, TraceId, StateClient, StateInfo, Call, BlockId};
use rlp::UntrustedRlp;
use transaction::SignedTransaction;
@ -27,7 +27,7 @@ use jsonrpc_macros::Trailing;
use v1::Metadata;
use v1::traits::Traces;
use v1::helpers::{errors, fake_sign};
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256};
use v1::types::{TraceFilter, LocalizedTrace, BlockNumber, Index, CallRequest, Bytes, TraceResults, TraceOptions, H256, block_number_to_id};
fn to_call_analytics(flags: TraceOptions) -> CallAnalytics {
CallAnalytics {
@ -51,7 +51,10 @@ impl<C> TracesClient<C> {
}
}
impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static {
impl<C, S> Traces for TracesClient<C> where
S: StateInfo + 'static,
C: MiningBlockChainClient + StateClient<State=S> + Call<State=S> + 'static
{
type Metadata = Metadata;
fn filter(&self, filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>> {
@ -60,7 +63,12 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static {
}
fn block_traces(&self, block_number: BlockNumber) -> Result<Option<Vec<LocalizedTrace>>> {
Ok(self.client.block_traces(block_number.into())
let id = match block_number {
BlockNumber::Pending => return Ok(None),
num => block_number_to_id(num)
};
Ok(self.client.block_traces(id)
.map(|traces| traces.into_iter().map(LocalizedTrace::from).collect()))
}
@ -85,7 +93,18 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static {
let request = CallRequest::into(request);
let signed = fake_sign::sign_call(request, meta.is_dapp())?;
self.client.call(&signed, to_call_analytics(flags), block.into())
let id = match block {
BlockNumber::Num(num) => BlockId::Number(num),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => return Err(errors::invalid_params("`BlockNumber::Pending` is not supported", ())),
};
let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?;
let header = self.client.block_header(id).ok_or(errors::state_pruned())?;
self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode())
.map(TraceResults::from)
.map_err(errors::call)
}
@ -101,7 +120,18 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static {
})
.collect::<Result<Vec<_>>>()?;
self.client.call_many(&requests, block.into())
let id = match block {
BlockNumber::Num(num) => BlockId::Number(num),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => return Err(errors::invalid_params("`BlockNumber::Pending` is not supported", ())),
};
let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?;
let header = self.client.block_header(id).ok_or(errors::state_pruned())?;
self.client.call_many(&requests, &mut state, &header.decode())
.map(|results| results.into_iter().map(TraceResults::from).collect())
.map_err(errors::call)
}
@ -112,7 +142,18 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static {
let tx = UntrustedRlp::new(&raw_transaction.into_vec()).as_val().map_err(|e| errors::invalid_params("Transaction is not valid RLP", e))?;
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
self.client.call(&signed, to_call_analytics(flags), block.into())
let id = match block {
BlockNumber::Num(num) => BlockId::Number(num),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => return Err(errors::invalid_params("`BlockNumber::Pending` is not supported", ())),
};
let mut state = self.client.state_at(id).ok_or(errors::state_pruned())?;
let header = self.client.block_header(id).ok_or(errors::state_pruned())?;
self.client.call(&signed, to_call_analytics(flags), &mut state, &header.decode())
.map(TraceResults::from)
.map_err(errors::call)
}
@ -124,7 +165,15 @@ impl<C> Traces for TracesClient<C> where C: MiningBlockChainClient + 'static {
}
fn replay_block_transactions(&self, block_number: BlockNumber, flags: TraceOptions) -> Result<Vec<TraceResults>> {
self.client.replay_block_transactions(block_number.into(), to_call_analytics(flags))
let id = match block_number {
BlockNumber::Num(num) => BlockId::Number(num),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => return Err(errors::invalid_params("`BlockNumber::Pending` is not supported", ())),
};
self.client.replay_block_transactions(id, to_call_analytics(flags))
.map(|results| results.into_iter().map(TraceResults::from).collect())
.map_err(errors::call)
}

View File

@ -22,10 +22,10 @@ use std::time::Duration;
use ethereum_types::{U256, H256, Address};
use ethcore::account_provider::AccountProvider;
use ethcore::block::Block;
use ethcore::client::{BlockChainClient, Client, ClientConfig};
use ethcore::client::{BlockChainClient, Client, ClientConfig, ChainInfo, ImportBlock};
use ethcore::ethereum;
use ethcore::ids::BlockId;
use ethcore::miner::{MinerOptions, Banning, GasPricer, MinerService, Miner, PendingSet, GasLimit};
use ethcore::miner::{MinerOptions, Banning, GasPricer, Miner, PendingSet, GasLimit};
use ethcore::spec::{Genesis, Spec};
use ethcore::views::BlockView;
use ethjson::blockchain::BlockChain;
@ -101,7 +101,7 @@ fn make_spec(chain: &BlockChain) -> Spec {
struct EthTester {
client: Arc<Client>,
_miner: Arc<MinerService>,
_miner: Arc<Miner>,
_snapshot: Arc<TestSnapshotService>,
accounts: Arc<AccountProvider>,
handler: IoHandler<Metadata>,

View File

@ -18,16 +18,19 @@
use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map::Entry;
use ethereum_types::{H256, U256, Address};
use bytes::Bytes;
use ethcore::account_provider::SignError as AccountError;
use ethcore::block::ClosedBlock;
use ethcore::client::MiningBlockChainClient;
use ethcore::block::{Block, ClosedBlock};
use ethcore::client::{Nonce, PrepareOpenBlock, StateClient, EngineInfo};
use ethcore::engines::EthEngine;
use ethcore::error::Error;
use ethcore::header::BlockNumber;
use ethcore::header::{BlockNumber, Header};
use ethcore::ids::BlockId;
use ethcore::miner::{MinerService, MinerStatus};
use miner::local_transactions::Status as LocalTransactionStatus;
use ethcore::receipt::{Receipt, RichReceipt};
use ethereum_types::{H256, U256, Address};
use miner::local_transactions::Status as LocalTransactionStatus;
use parking_lot::{RwLock, Mutex};
use transaction::{UnverifiedTransaction, SignedTransaction, PendingTransaction, ImportResult as TransactionImportResult};
@ -92,7 +95,39 @@ impl TestMinerService {
}
}
impl StateClient for TestMinerService {
// State will not be used by test client anyway, since all methods that accept state are mocked
type State = ();
fn latest_state(&self) -> Self::State {
()
}
fn state_at(&self, _id: BlockId) -> Option<Self::State> {
Some(())
}
}
impl EngineInfo for TestMinerService {
fn engine(&self) -> &EthEngine {
unimplemented!()
}
}
impl MinerService for TestMinerService {
type State = ();
fn pending_state(&self, _latest_block_number: BlockNumber) -> Option<Self::State> {
None
}
fn pending_block_header(&self, _latest_block_number: BlockNumber) -> Option<Header> {
None
}
fn pending_block(&self, _latest_block_number: BlockNumber) -> Option<Block> {
None
}
/// Returns miner's status.
fn status(&self) -> MinerStatus {
@ -164,7 +199,7 @@ impl MinerService for TestMinerService {
}
/// Imports transactions to transaction queue.
fn import_external_transactions(&self, _chain: &MiningBlockChainClient, transactions: Vec<UnverifiedTransaction>) ->
fn import_external_transactions<C>(&self, _chain: &C, transactions: Vec<UnverifiedTransaction>) ->
Vec<Result<TransactionImportResult, Error>> {
// lets assume that all txs are valid
let transactions: Vec<_> = transactions.into_iter().map(|tx| SignedTransaction::new(tx).unwrap()).collect();
@ -181,7 +216,7 @@ impl MinerService for TestMinerService {
}
/// Imports transactions to transaction queue.
fn import_own_transaction(&self, chain: &MiningBlockChainClient, pending: PendingTransaction) ->
fn import_own_transaction<C: Nonce>(&self, chain: &C, pending: PendingTransaction) ->
Result<TransactionImportResult, Error> {
// keep the pending nonces up to date
@ -201,12 +236,12 @@ impl MinerService for TestMinerService {
}
/// Removes all transactions from the queue and restart mining operation.
fn clear_and_reset(&self, _chain: &MiningBlockChainClient) {
fn clear_and_reset<C>(&self, _chain: &C) {
unimplemented!();
}
/// Called when blocks are imported to chain, updates transactions queue.
fn chain_new_blocks(&self, _chain: &MiningBlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) {
fn chain_new_blocks<C>(&self, _chain: &C, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) {
unimplemented!();
}
@ -216,11 +251,11 @@ impl MinerService for TestMinerService {
}
/// New chain head event. Restart mining operation.
fn update_sealing(&self, _chain: &MiningBlockChainClient) {
fn update_sealing<C>(&self, _chain: &C) {
unimplemented!();
}
fn map_sealing_work<F, T>(&self, chain: &MiningBlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
fn map_sealing_work<C: PrepareOpenBlock, F, T>(&self, chain: &C, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
let open_block = chain.prepare_open_block(self.author(), *self.gas_range_target.write(), self.extra_data());
Some(f(&open_block.close()))
}
@ -229,7 +264,7 @@ impl MinerService for TestMinerService {
self.pending_transactions.lock().get(hash).cloned().map(Into::into)
}
fn remove_pending_transaction(&self, _chain: &MiningBlockChainClient, hash: &H256) -> Option<PendingTransaction> {
fn remove_pending_transaction<C>(&self, _chain: &C, hash: &H256) -> Option<PendingTransaction> {
self.pending_transactions.lock().remove(hash).map(Into::into)
}
@ -279,7 +314,7 @@ impl MinerService for TestMinerService {
/// Submit `seal` as a valid solution for the header of `pow_hash`.
/// Will check the seal, but not actually insert the block into the chain.
fn submit_seal(&self, _chain: &MiningBlockChainClient, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> {
fn submit_seal<C>(&self, _chain: &C, _pow_hash: H256, _seal: Vec<Bytes>) -> Result<(), Error> {
unimplemented!();
}

View File

@ -82,7 +82,7 @@ fn should_subscribe_to_new_heads() {
fn should_subscribe_to_logs() {
use ethcore::log_entry::{LocalizedLogEntry, LogEntry};
use ethcore::ids::BlockId;
use ethcore::client::BlockChainClient;
use ethcore::client::BlockInfo;
// given
let el = EventLoop::spawn();

View File

@ -91,14 +91,14 @@ impl<'a> Visitor<'a> for BlockNumberVisitor {
}
}
impl Into<BlockId> for BlockNumber {
fn into(self) -> BlockId {
match self {
BlockNumber::Num(n) => BlockId::Number(n),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => BlockId::Pending,
}
/// Converts `BlockNumber` to `BlockId`, panics on `BlockNumber::Pending`
pub fn block_number_to_id(number: BlockNumber) -> BlockId {
match number {
BlockNumber::Num(num) => BlockId::Number(num),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => panic!("`BlockNumber::Pending` should be handled manually")
}
}
@ -122,11 +122,17 @@ mod tests {
}
#[test]
fn block_number_into() {
assert_eq!(BlockId::Number(100), BlockNumber::Num(100).into());
assert_eq!(BlockId::Earliest, BlockNumber::Earliest.into());
assert_eq!(BlockId::Latest, BlockNumber::Latest.into());
assert_eq!(BlockId::Pending, BlockNumber::Pending.into());
fn normal_block_number_to_id() {
assert_eq!(block_number_to_id(BlockNumber::Num(100)), BlockId::Number(100));
assert_eq!(block_number_to_id(BlockNumber::Earliest), BlockId::Earliest);
assert_eq!(block_number_to_id(BlockNumber::Latest), BlockId::Latest);
}
#[test]
#[should_panic]
fn pending_block_number_to_id() {
// Since this function is not allowed to be called in such way, panic should happen
block_number_to_id(BlockNumber::Pending);
}
}

View File

@ -72,9 +72,15 @@ pub struct Filter {
impl Into<EthFilter> for Filter {
fn into(self) -> EthFilter {
let num_to_id = |num| match num {
BlockNumber::Num(n) => BlockId::Number(n),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest,
};
EthFilter {
from_block: self.from_block.map_or_else(|| BlockId::Latest, Into::into),
to_block: self.to_block.map_or_else(|| BlockId::Latest, Into::into),
from_block: self.from_block.map_or_else(|| BlockId::Latest, &num_to_id),
to_block: self.to_block.map_or_else(|| BlockId::Latest, &num_to_id),
address: self.address.and_then(|address| match address {
VariadicValue::Null => None,
VariadicValue::Single(a) => Some(vec![a.into()]),

View File

@ -50,7 +50,7 @@ pub mod pubsub;
pub use self::account_info::{AccountInfo, ExtAccountInfo, HwAccountInfo};
pub use self::bytes::Bytes;
pub use self::block::{RichBlock, Block, BlockTransactions, Header, RichHeader, Rich};
pub use self::block_number::BlockNumber;
pub use self::block_number::{BlockNumber, block_number_to_id};
pub use self::call_request::CallRequest;
pub use self::confirmations::{
ConfirmationPayload, ConfirmationRequest, ConfirmationResponse, ConfirmationResponseWithToken,

View File

@ -44,8 +44,17 @@ pub struct TraceFilter {
impl Into<client::TraceFilter> for TraceFilter {
fn into(self) -> client::TraceFilter {
let start = self.from_block.map_or(BlockId::Latest, Into::into);
let end = self.to_block.map_or(BlockId::Latest, Into::into);
let num_to_id = |num| match num {
BlockNumber::Num(n) => BlockId::Number(n),
BlockNumber::Earliest => BlockId::Earliest,
BlockNumber::Latest => BlockId::Latest,
BlockNumber::Pending => {
warn!("Pending traces are not supported and might be removed in future versions. Falling back to Latest");
BlockId::Latest
}
};
let start = self.from_block.map_or(BlockId::Latest, &num_to_id);
let end = self.to_block.map_or(BlockId::Latest, &num_to_id);
client::TraceFilter {
range: start..end,
from_address: self.from_address.map_or_else(Vec::new, |x| x.into_iter().map(Into::into).collect()),

View File

@ -18,7 +18,7 @@ use std::sync::Arc;
use std::collections::{HashMap, HashSet};
use parking_lot::{Mutex, RwLock};
use ethkey::public_to_address;
use ethcore::client::{BlockChainClient, BlockId, ChainNotify};
use ethcore::client::{BlockId, ChainNotify, CallContract, RegistryInfo};
use ethereum_types::{H256, Address};
use bytes::Bytes;
use trusted_client::TrustedClient;

View File

@ -18,8 +18,8 @@ use std::sync::Arc;
use std::net::SocketAddr;
use std::collections::{BTreeMap, HashSet};
use parking_lot::Mutex;
use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify, CallContract, RegistryInfo};
use ethcore::filter::Filter;
use ethcore::client::{Client, BlockChainClient, BlockId, ChainNotify};
use ethkey::public_to_address;
use hash::keccak;
use ethereum_types::{H256, Address};
@ -281,7 +281,7 @@ impl CachedContract {
fn start_migration(&mut self, migration_id: H256) {
// trust is not needed here, because it is the reaction to the read of the trusted client
if let (Some(client), Some(contract_address)) = (self.client.get_untrusted(), self.contract_address) {
if let (Some(client), Some(contract_address)) = (self.client.get_untrusted(), self.contract_address.as_ref()) {
// check if we need to send start migration transaction
if !update_last_transaction_block(&*client, &migration_id, &mut self.start_migration_tx) {
return;
@ -291,7 +291,7 @@ impl CachedContract {
let transaction_data = self.contract.functions().start_migration().input(migration_id);
// send transaction
if let Err(error) = client.transact_contract(contract_address, transaction_data) {
if let Err(error) = client.transact_contract(*contract_address, transaction_data) {
warn!(target: "secretstore_net", "{}: failed to submit auto-migration start transaction: {}",
self.self_key_pair.public(), error);
} else {

View File

@ -17,7 +17,7 @@
use std::sync::Arc;
use parking_lot::RwLock;
use ethcore::filter::Filter;
use ethcore::client::{Client, BlockChainClient, BlockId};
use ethcore::client::{Client, BlockChainClient, BlockId, RegistryInfo, CallContract};
use ethkey::{Public, Signature, public_to_address};
use hash::keccak;
use ethereum_types::{H256, U256, Address};

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::{Arc, Weak};
use ethcore::client::{Client, BlockChainClient};
use ethcore::client::{Client, BlockChainClient, ChainInfo};
use ethsync::SyncProvider;
#[derive(Clone)]

View File

@ -2232,7 +2232,7 @@ mod tests {
use ::SyncConfig;
use super::{PeerInfo, PeerAsking};
use ethcore::header::*;
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient};
use ethcore::client::{BlockChainClient, EachBlockWith, TestBlockChainClient, ChainInfo, BlockInfo};
use ethcore::miner::MinerService;
use transaction::UnverifiedTransaction;

View File

@ -16,7 +16,7 @@
use tests::helpers::TestNet;
use ethcore::client::{BlockChainClient, BlockId, EachBlockWith};
use ethcore::client::{BlockInfo, BlockId, EachBlockWith};
mod test_net;

View File

@ -15,7 +15,7 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use ethcore::client::{TestBlockChainClient, BlockChainClient, BlockId, EachBlockWith};
use ethcore::client::{TestBlockChainClient, BlockChainClient, BlockId, EachBlockWith, ChainInfo, BlockInfo};
use chain::{SyncState};
use super::helpers::*;
use SyncConfig;

View File

@ -18,7 +18,7 @@ use std::sync::Arc;
use hash::keccak;
use ethereum_types::{U256, Address};
use io::{IoHandler, IoContext, IoChannel};
use ethcore::client::{BlockChainClient, Client};
use ethcore::client::{Client, ChainInfo};
use ethcore::service::ClientIoMessage;
use ethcore::spec::Spec;
use ethcore::miner::MinerService;

View File

@ -52,7 +52,7 @@ pub mod overlaydb;
/// Export the `JournalDB` trait.
pub use self::traits::JournalDB;
/// A journal database algorithm.
/// Journal database operating strategy.
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum Algorithm {
/// Keep all keys forever.