proofs of non-existance in ProvingBlockChainClient

This commit is contained in:
Robert Habermeier 2017-03-06 17:03:58 +01:00
parent 41effadb94
commit 8e9faa416d
5 changed files with 40 additions and 60 deletions

View File

@ -1585,23 +1585,14 @@ impl MayPanic for Client {
}
impl ::client::ProvingBlockChainClient for Client {
fn prove_storage(&self, key1: H256, key2: H256, from_level: u32, id: BlockId) -> Vec<Bytes> {
fn prove_storage(&self, key1: H256, key2: H256, id: BlockId) -> Option<(Vec<Bytes>, H256)> {
self.state_at(id)
.and_then(move |state| state.prove_storage(key1, key2, from_level).ok())
.unwrap_or_else(Vec::new)
.and_then(move |state| state.prove_storage(key1, key2).ok())
}
fn prove_account(&self, key1: H256, from_level: u32, id: BlockId) -> Vec<Bytes> {
fn prove_account(&self, key1: H256, id: BlockId) -> Option<(Vec<Bytes>, ::types::basic_account::BasicAccount)> {
self.state_at(id)
.and_then(move |state| state.prove_account(key1, from_level).ok())
.unwrap_or_else(Vec::new)
}
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)
.and_then(move |state| state.prove_account(key1).ok())
}
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<Vec<DBValue>> {

View File

@ -38,6 +38,7 @@ use error::{ImportResult, Error as EthcoreError};
use evm::{Factory as EvmFactory, VMType, Schedule};
use miner::{Miner, MinerService, TransactionImportResult};
use spec::Spec;
use types::basic_account::BasicAccount;
use types::mode::Mode;
use types::pruning_info::PruningInfo;
@ -754,16 +755,12 @@ impl BlockChainClient for TestBlockChainClient {
}
impl ProvingBlockChainClient for TestBlockChainClient {
fn prove_storage(&self, _: H256, _: H256, _: u32, _: BlockId) -> Vec<Bytes> {
Vec::new()
fn prove_storage(&self, _: H256, _: H256, _: BlockId) -> Option<(Vec<Bytes>, H256)> {
None
}
fn prove_account(&self, _: H256, _: u32, _: BlockId) -> Vec<Bytes> {
Vec::new()
}
fn code_by_hash(&self, _: H256, _: BlockId) -> Bytes {
Vec::new()
fn prove_account(&self, _: H256, _: BlockId) -> Option<(Vec<Bytes>, BasicAccount)> {
None
}
fn prove_transaction(&self, _: SignedTransaction, _: BlockId) -> Option<Vec<DBValue>> {

View File

@ -34,6 +34,7 @@ use env_info::LastHashes;
use block_import_error::BlockImportError;
use ipc::IpcConfig;
use types::ids::*;
use types::basic_account::BasicAccount;
use types::trace_filter::Filter as TraceFilter;
use types::call_analytics::CallAnalytics;
use types::blockchain_info::BlockChainInfo;
@ -309,19 +310,12 @@ pub trait ProvingBlockChainClient: BlockChainClient {
///
/// 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>;
fn prove_storage(&self, key1: H256, key2: H256, id: BlockId) -> Option<(Vec<Bytes>, H256)>;
/// 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;
fn prove_account(&self, key1: H256, id: BlockId) -> Option<(Vec<Bytes>, BasicAccount)>;
/// Prove execution of a transaction at the given block.
fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option<Vec<DBValue>>;

View File

@ -438,18 +438,19 @@ impl Account {
/// 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>> {
pub fn prove_storage(&self, db: &HashDB, storage_key: H256) -> Result<(Vec<Bytes>, H256), Box<TrieError>> {
use util::trie::{Trie, TrieDB};
use util::trie::recorder::Recorder;
let mut recorder = Recorder::with_depth(from_level);
let mut recorder = Recorder::new();
let trie = TrieDB::new(db, &self.storage_root)?;
let _ = trie.get_with(&storage_key, &mut recorder)?;
let item: U256 = {
let query = (&mut recorder, ::rlp::decode);
trie.get_with(&storage_key, query)?.unwrap_or_else(U256::zero)
};
Ok(recorder.drain().into_iter().map(|r| r.data).collect())
Ok((recorder.drain().into_iter().map(|r| r.data).collect(), item.into()))
}
}

View File

@ -31,6 +31,7 @@ use factory::Factories;
use trace::FlatTrace;
use pod_account::*;
use pod_state::{self, PodState};
use types::basic_account::BasicAccount;
use types::executed::{Executed, ExecutionError};
use types::state_diff::StateDiff;
use transaction::SignedTransaction;
@ -857,47 +858,43 @@ impl<B: Backend> State<B> {
// State proof implementations; useful for light client protocols.
impl<B: Backend> State<B> {
/// 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.
/// Returns a merkle proof of the account's trie node omitted or an encountered trie error.
/// If the account doesn't exist in the trie, prove that and return defaults.
/// 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) -> trie::Result<Vec<Bytes>> {
let mut recorder = Recorder::with_depth(from_level);
pub fn prove_account(&self, account_key: H256) -> trie::Result<(Vec<Bytes>, BasicAccount)> {
let mut recorder = Recorder::new();
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
trie.get_with(&account_key, &mut recorder)?;
let maybe_account: Option<BasicAccount> = {
let query = (&mut recorder, ::rlp::decode);
trie.get_with(&account_key, query)?
};
let account = maybe_account.unwrap_or_else(|| BasicAccount {
balance: 0.into(),
nonce: self.account_start_nonce,
code_hash: SHA3_EMPTY,
storage_root: ::util::sha3::SHA3_NULL_RLP,
});
Ok(recorder.drain().into_iter().map(|r| r.data).collect())
Ok((recorder.drain().into_iter().map(|r| r.data).collect(), account))
}
/// 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.
/// Returns a merkle proof of the account's storage trie.
/// 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) -> trie::Result<Vec<Bytes>> {
pub fn prove_storage(&self, account_key: H256, storage_key: H256) -> trie::Result<(Vec<Bytes>, H256)> {
// TODO: probably could look into cache somehow but it's keyed by
// address, not sha3(address).
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
let acc = match trie.get_with(&account_key, Account::from_rlp)? {
Some(acc) => acc,
None => return Ok(Vec::new()),
None => return Ok((Vec::new(), H256::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) -> trie::Result<Option<Bytes>> {
let trie = TrieDB::new(self.db.as_hashdb(), &self.root)?;
let mut acc = match trie.get_with(&account_key, Account::from_rlp)? {
Some(acc) => acc,
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()))
acc.prove_storage(account_db.as_hashdb(), storage_key)
}
}