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:
parent
81b52c7336
commit
9d7d6f7108
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -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",
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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};
|
||||
|
@ -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)
|
||||
|
@ -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
@ -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;
|
||||
|
@ -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> {
|
||||
|
@ -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>;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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())
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
@ -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);
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.";
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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>>,
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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),
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
&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.
|
||||
|
@ -31,8 +31,6 @@ pub enum BlockId {
|
||||
Earliest,
|
||||
/// Latest mined block.
|
||||
Latest,
|
||||
/// Pending block.
|
||||
Pending,
|
||||
}
|
||||
|
||||
/// Uniquely identifies transaction.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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};
|
||||
|
@ -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" }
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
};
|
||||
|
@ -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,31 +246,111 @@ 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) {
|
||||
|
||||
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()))
|
||||
.map(|block| block.into_inner().len())
|
||||
.map(U256::from)
|
||||
@ -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"))
|
||||
}
|
||||
},
|
||||
|
||||
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"))
|
||||
}
|
||||
id => {
|
||||
try_bf!(check_known(&*self.client, id.clone()));
|
||||
match self.client.nonce(&address, id.into()) {
|
||||
},
|
||||
|
||||
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)
|
||||
))
|
||||
|
@ -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)
|
||||
}))
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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>,
|
||||
|
@ -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!();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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),
|
||||
/// 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 => BlockId::Pending,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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()]),
|
||||
|
@ -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,
|
||||
|
@ -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()),
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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};
|
||||
|
@ -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)]
|
||||
|
@ -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;
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
use tests::helpers::TestNet;
|
||||
|
||||
use ethcore::client::{BlockChainClient, BlockId, EachBlockWith};
|
||||
use ethcore::client::{BlockInfo, BlockId, EachBlockWith};
|
||||
|
||||
mod test_net;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user