From 8e9faa416da13b70e9dbc751b6285925bce77382 Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Mon, 6 Mar 2017 17:03:58 +0100 Subject: [PATCH] proofs of non-existance in ProvingBlockChainClient --- ethcore/src/client/client.rs | 17 +++--------- ethcore/src/client/test_client.rs | 13 ++++----- ethcore/src/client/traits.rs | 12 +++------ ethcore/src/state/account.rs | 13 ++++----- ethcore/src/state/mod.rs | 45 +++++++++++++++---------------- 5 files changed, 40 insertions(+), 60 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 63be1da07..54e433a72 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -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 { + fn prove_storage(&self, key1: H256, key2: H256, id: BlockId) -> Option<(Vec, 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 { + fn prove_account(&self, key1: H256, id: BlockId) -> Option<(Vec, ::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> { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index 5d436f4c5..79783175d 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -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 { - Vec::new() + fn prove_storage(&self, _: H256, _: H256, _: BlockId) -> Option<(Vec, H256)> { + None } - fn prove_account(&self, _: H256, _: u32, _: BlockId) -> Vec { - Vec::new() - } - - fn code_by_hash(&self, _: H256, _: BlockId) -> Bytes { - Vec::new() + fn prove_account(&self, _: H256, _: BlockId) -> Option<(Vec, BasicAccount)> { + None } fn prove_transaction(&self, _: SignedTransaction, _: BlockId) -> Option> { diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index 4af20de0f..145398ef6 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -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; + fn prove_storage(&self, key1: H256, key2: H256, id: BlockId) -> Option<(Vec, 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; - - /// 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, BasicAccount)>; /// Prove execution of a transaction at the given block. fn prove_transaction(&self, transaction: SignedTransaction, id: BlockId) -> Option>; diff --git a/ethcore/src/state/account.rs b/ethcore/src/state/account.rs index ebdf36d89..51f7e3b98 100644 --- a/ethcore/src/state/account.rs +++ b/ethcore/src/state/account.rs @@ -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, Box> { + pub fn prove_storage(&self, db: &HashDB, storage_key: H256) -> Result<(Vec, H256), Box> { 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())) } } diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 3c5a3bc09..745fb2980 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -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 State { // State proof implementations; useful for light client protocols. 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. + /// 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> { - let mut recorder = Recorder::with_depth(from_level); + pub fn prove_account(&self, account_key: H256) -> trie::Result<(Vec, 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 = { + 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> { + pub fn prove_storage(&self, account_key: H256, storage_key: H256) -> trie::Result<(Vec, 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> { - 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) } }