Merge branch 'master' into auth-bft
This commit is contained in:
@@ -52,7 +52,7 @@ use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute};
|
||||
use client::{
|
||||
BlockID, TransactionID, UncleID, TraceId, ClientConfig, BlockChainClient,
|
||||
MiningBlockChainClient, TraceFilter, CallAnalytics, BlockImportError, Mode,
|
||||
ChainNotify,
|
||||
ChainNotify, PruningInfo, ProvingBlockChainClient,
|
||||
};
|
||||
use client::Error as ClientError;
|
||||
use env_info::EnvInfo;
|
||||
@@ -1311,6 +1311,13 @@ impl BlockChainClient for Client {
|
||||
self.uncle(id)
|
||||
.map(|header| self.engine.extra_info(&decode(&header)))
|
||||
}
|
||||
|
||||
fn pruning_info(&self) -> PruningInfo {
|
||||
PruningInfo {
|
||||
earliest_chain: self.chain.read().first_block_number().unwrap_or(1),
|
||||
earliest_state: self.state_db.lock().journal_db().earliest_era().unwrap_or(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MiningBlockChainClient for Client {
|
||||
@@ -1395,32 +1402,60 @@ impl MayPanic for Client {
|
||||
}
|
||||
}
|
||||
|
||||
impl ProvingBlockChainClient for Client {
|
||||
fn prove_storage(&self, key1: H256, key2: H256, from_level: u32, id: BlockID) -> Vec<Bytes> {
|
||||
self.state_at(id)
|
||||
.and_then(move |state| state.prove_storage(key1, key2, from_level).ok())
|
||||
.unwrap_or_else(Vec::new)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_not_cache_details_before_commit() {
|
||||
use tests::helpers::*;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
fn prove_account(&self, key1: H256, from_level: u32, id: BlockID) -> Vec<Bytes> {
|
||||
self.state_at(id)
|
||||
.and_then(move |state| state.prove_account(key1, from_level).ok())
|
||||
.unwrap_or_else(Vec::new)
|
||||
}
|
||||
|
||||
let client = generate_dummy_client(0);
|
||||
let genesis = client.chain_info().best_block_hash;
|
||||
let (new_hash, new_block) = get_good_dummy_block_hash();
|
||||
|
||||
let go = {
|
||||
// Separate thread uncommited transaction
|
||||
let go = Arc::new(AtomicBool::new(false));
|
||||
let go_thread = go.clone();
|
||||
let another_client = client.reference().clone();
|
||||
thread::spawn(move || {
|
||||
let mut batch = DBTransaction::new(&*another_client.chain.read().db().clone());
|
||||
another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new());
|
||||
go_thread.store(true, Ordering::SeqCst);
|
||||
});
|
||||
go
|
||||
};
|
||||
|
||||
while !go.load(Ordering::SeqCst) { thread::park_timeout(Duration::from_millis(5)); }
|
||||
|
||||
assert!(client.tree_route(&genesis, &new_hash).is_none());
|
||||
fn code_by_hash(&self, account_key: H256, id: BlockID) -> Bytes {
|
||||
self.state_at(id)
|
||||
.and_then(move |state| state.code_by_address_hash(account_key).ok())
|
||||
.and_then(|x| x)
|
||||
.unwrap_or_else(Vec::new)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
#[test]
|
||||
fn should_not_cache_details_before_commit() {
|
||||
use client::BlockChainClient;
|
||||
use tests::helpers::*;
|
||||
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use util::kvdb::DBTransaction;
|
||||
|
||||
let client = generate_dummy_client(0);
|
||||
let genesis = client.chain_info().best_block_hash;
|
||||
let (new_hash, new_block) = get_good_dummy_block_hash();
|
||||
|
||||
let go = {
|
||||
// Separate thread uncommited transaction
|
||||
let go = Arc::new(AtomicBool::new(false));
|
||||
let go_thread = go.clone();
|
||||
let another_client = client.reference().clone();
|
||||
thread::spawn(move || {
|
||||
let mut batch = DBTransaction::new(&*another_client.chain.read().db().clone());
|
||||
another_client.chain.read().insert_block(&mut batch, &new_block, Vec::new());
|
||||
go_thread.store(true, Ordering::SeqCst);
|
||||
});
|
||||
go
|
||||
};
|
||||
|
||||
while !go.load(Ordering::SeqCst) { thread::park_timeout(Duration::from_millis(5)); }
|
||||
|
||||
assert!(client.tree_route(&genesis, &new_hash).is_none());
|
||||
}
|
||||
}
|
||||
@@ -25,18 +25,21 @@ mod client;
|
||||
pub use self::client::*;
|
||||
pub use self::config::{Mode, ClientConfig, DatabaseCompactionProfile, BlockChainConfig, VMType};
|
||||
pub use self::error::Error;
|
||||
pub use types::ids::*;
|
||||
pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
||||
pub use self::chain_notify::ChainNotify;
|
||||
pub use self::traits::{BlockChainClient, MiningBlockChainClient, ProvingBlockChainClient};
|
||||
|
||||
pub use types::ids::*;
|
||||
pub use types::trace_filter::Filter as TraceFilter;
|
||||
pub use types::pruning_info::PruningInfo;
|
||||
pub use types::call_analytics::CallAnalytics;
|
||||
|
||||
pub use executive::{Executed, Executive, TransactOptions};
|
||||
pub use env_info::{LastHashes, EnvInfo};
|
||||
pub use self::chain_notify::ChainNotify;
|
||||
|
||||
pub use types::call_analytics::CallAnalytics;
|
||||
pub use block_import_error::BlockImportError;
|
||||
pub use transaction_import::TransactionImportResult;
|
||||
pub use transaction_import::TransactionImportError;
|
||||
pub use self::traits::{BlockChainClient, MiningBlockChainClient};
|
||||
pub use verification::VerifierType;
|
||||
|
||||
/// IPC interfaces
|
||||
|
||||
@@ -38,6 +38,7 @@ use evm::{Factory as EvmFactory, VMType, Schedule};
|
||||
use miner::{Miner, MinerService, TransactionImportResult};
|
||||
use spec::Spec;
|
||||
use types::mode::Mode;
|
||||
use types::pruning_info::PruningInfo;
|
||||
use views::BlockView;
|
||||
|
||||
use verification::queue::QueueInfo;
|
||||
@@ -671,4 +672,11 @@ impl BlockChainClient for TestBlockChainClient {
|
||||
fn mode(&self) -> Mode { Mode::Active }
|
||||
|
||||
fn set_mode(&self, _: Mode) { unimplemented!(); }
|
||||
|
||||
fn pruning_info(&self) -> PruningInfo {
|
||||
PruningInfo {
|
||||
earliest_chain: 1,
|
||||
earliest_state: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ use types::call_analytics::CallAnalytics;
|
||||
use types::blockchain_info::BlockChainInfo;
|
||||
use types::block_status::BlockStatus;
|
||||
use types::mode::Mode;
|
||||
use types::pruning_info::PruningInfo;
|
||||
|
||||
#[ipc(client_ident="RemoteClient")]
|
||||
/// Blockchain database client. Owns and manages a blockchain and a block queue.
|
||||
@@ -253,10 +254,15 @@ pub trait BlockChainClient : Sync + Send {
|
||||
|
||||
/// Returns engine-related extra info for `UncleID`.
|
||||
fn uncle_extra_info(&self, id: UncleID) -> Option<BTreeMap<String, String>>;
|
||||
|
||||
/// Returns information about pruning/data availability.
|
||||
fn pruning_info(&self) -> PruningInfo;
|
||||
}
|
||||
|
||||
impl IpcConfig for BlockChainClient { }
|
||||
|
||||
/// Extended client interface used for mining
|
||||
pub trait MiningBlockChainClient : BlockChainClient {
|
||||
pub trait MiningBlockChainClient: BlockChainClient {
|
||||
/// Returns OpenBlock prepared for closing.
|
||||
fn prepare_open_block(&self,
|
||||
author: Address,
|
||||
@@ -274,4 +280,23 @@ pub trait MiningBlockChainClient : BlockChainClient {
|
||||
fn latest_schedule(&self) -> Schedule;
|
||||
}
|
||||
|
||||
impl IpcConfig for BlockChainClient { }
|
||||
/// Extended client interface for providing proofs of the state.
|
||||
pub trait ProvingBlockChainClient: BlockChainClient {
|
||||
/// Prove account storage at a specific block id.
|
||||
///
|
||||
/// Both provided keys assume a secure trie.
|
||||
/// Returns a vector of raw trie nodes (in order from the root) proving the storage query.
|
||||
/// Nodes after `from_level` may be omitted.
|
||||
/// An empty vector indicates unservable query.
|
||||
fn prove_storage(&self, key1: H256, key2: H256, from_level: u32, id: BlockID) -> Vec<Bytes>;
|
||||
|
||||
/// Prove account existence at a specific block id.
|
||||
/// The key is the keccak hash of the account's address.
|
||||
/// Returns a vector of raw trie nodes (in order from the root) proving the query.
|
||||
/// Nodes after `from_level` may be omitted.
|
||||
/// An empty vector indicates unservable query.
|
||||
fn prove_account(&self, key1: H256, from_level: u32, id: BlockID) -> Vec<Bytes>;
|
||||
|
||||
/// Get code by address hash.
|
||||
fn code_by_hash(&self, account_key: H256, id: BlockID) -> Bytes;
|
||||
}
|
||||
@@ -436,6 +436,27 @@ impl Account {
|
||||
}
|
||||
}
|
||||
|
||||
// light client storage proof.
|
||||
impl Account {
|
||||
/// Prove a storage key's existence or nonexistence in the account's storage
|
||||
/// trie.
|
||||
/// `storage_key` is the hash of the desired storage key, meaning
|
||||
/// this will only work correctly under a secure trie.
|
||||
/// Returns a merkle proof of the storage trie node with all nodes before `from_level`
|
||||
/// omitted.
|
||||
pub fn prove_storage(&self, db: &HashDB, storage_key: H256, from_level: u32) -> Result<Vec<Bytes>, Box<TrieError>> {
|
||||
use util::trie::{Trie, TrieDB};
|
||||
use util::trie::recorder::{Recorder, BasicRecorder as TrieRecorder};
|
||||
|
||||
let mut recorder = TrieRecorder::with_depth(from_level);
|
||||
|
||||
let trie = try!(TrieDB::new(db, &self.storage_root));
|
||||
let _ = try!(trie.get_recorded(&storage_key, &mut recorder));
|
||||
|
||||
Ok(recorder.drain().into_iter().map(|r| r.data).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Account {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", PodAccount::from_account(self))
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::collections::hash_map::Entry;
|
||||
use util::*;
|
||||
|
||||
use receipt::Receipt;
|
||||
use engines::Engine;
|
||||
use env_info::EnvInfo;
|
||||
@@ -30,6 +30,9 @@ use types::state_diff::StateDiff;
|
||||
use transaction::SignedTransaction;
|
||||
use state_db::StateDB;
|
||||
|
||||
use util::*;
|
||||
use util::trie::recorder::{Recorder, BasicRecorder as TrieRecorder};
|
||||
|
||||
mod account;
|
||||
mod substate;
|
||||
|
||||
@@ -758,6 +761,53 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
// LES state proof implementations.
|
||||
impl State {
|
||||
/// Prove an account's existence or nonexistence in the state trie.
|
||||
/// Returns a merkle proof of the account's trie node with all nodes before `from_level`
|
||||
/// omitted or an encountered trie error.
|
||||
/// Requires a secure trie to be used for accurate results.
|
||||
/// `account_key` == sha3(address)
|
||||
pub fn prove_account(&self, account_key: H256, from_level: u32) -> Result<Vec<Bytes>, Box<TrieError>> {
|
||||
let mut recorder = TrieRecorder::with_depth(from_level);
|
||||
let trie = try!(TrieDB::new(self.db.as_hashdb(), &self.root));
|
||||
let _ = try!(trie.get_recorded(&account_key, &mut recorder));
|
||||
|
||||
Ok(recorder.drain().into_iter().map(|r| r.data).collect())
|
||||
}
|
||||
|
||||
/// Prove an account's storage key's existence or nonexistence in the state.
|
||||
/// Returns a merkle proof of the account's storage trie with all nodes before
|
||||
/// `from_level` omitted. Requires a secure trie to be used for correctness.
|
||||
/// `account_key` == sha3(address)
|
||||
/// `storage_key` == sha3(key)
|
||||
pub fn prove_storage(&self, account_key: H256, storage_key: H256, from_level: u32) -> Result<Vec<Bytes>, Box<TrieError>> {
|
||||
// TODO: probably could look into cache somehow but it's keyed by
|
||||
// address, not sha3(address).
|
||||
let trie = try!(TrieDB::new(self.db.as_hashdb(), &self.root));
|
||||
let acc = match try!(trie.get(&account_key)) {
|
||||
Some(rlp) => Account::from_rlp(&rlp),
|
||||
None => return Ok(Vec::new()),
|
||||
};
|
||||
|
||||
let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), account_key);
|
||||
acc.prove_storage(account_db.as_hashdb(), storage_key, from_level)
|
||||
}
|
||||
|
||||
/// Get code by address hash.
|
||||
/// Only works when backed by a secure trie.
|
||||
pub fn code_by_address_hash(&self, account_key: H256) -> Result<Option<Bytes>, Box<TrieError>> {
|
||||
let trie = try!(TrieDB::new(self.db.as_hashdb(), &self.root));
|
||||
let mut acc = match try!(trie.get(&account_key)) {
|
||||
Some(rlp) => Account::from_rlp(&rlp),
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
let account_db = self.factories.accountdb.readonly(self.db.as_hashdb(), account_key);
|
||||
Ok(acc.cache_code(account_db.as_hashdb()).map(|c| (&*c).clone()))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self.cache.borrow())
|
||||
|
||||
@@ -34,3 +34,4 @@ pub mod block_import_error;
|
||||
pub mod restoration_status;
|
||||
pub mod snapshot_manifest;
|
||||
pub mod mode;
|
||||
pub mod pruning_info;
|
||||
30
ethcore/src/types/pruning_info.rs
Normal file
30
ethcore/src/types/pruning_info.rs
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright 2015, 2016 Ethcore (UK) Ltd.
|
||||
// This file is part of Parity.
|
||||
|
||||
// Parity is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
|
||||
// Parity is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Information about portions of the state and chain which the client may serve.
|
||||
//!
|
||||
//! Currently assumes that a client will store everything past a certain point
|
||||
//! or everything. Will be extended in the future to support a definition
|
||||
//! of which portions of the ancient chain and current state trie are stored as well.
|
||||
|
||||
/// Client pruning info. See module-level docs for more details.
|
||||
#[derive(Debug, Clone, Binary)]
|
||||
pub struct PruningInfo {
|
||||
/// The first block which everything can be served after.
|
||||
pub earliest_chain: u64,
|
||||
/// The first block where state requests may be served.
|
||||
pub earliest_state: u64,
|
||||
}
|
||||
Reference in New Issue
Block a user