diff --git a/ethcore/client-traits/src/lib.rs b/ethcore/client-traits/src/lib.rs index a4ca2b29c..a579da636 100644 --- a/ethcore/client-traits/src/lib.rs +++ b/ethcore/client-traits/src/lib.rs @@ -67,6 +67,16 @@ pub enum StateOrBlock { Block(BlockId) } +/// Result to be used during get address code at given block's state +// todo[botika] move to `common-types` +pub enum StateResult { + /// State is missing + Missing, + + /// State is some + Some(T), +} + impl From> for StateOrBlock { fn from(info: Box) -> StateOrBlock { StateOrBlock::State(info) @@ -231,12 +241,14 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra fn block_hash(&self, id: BlockId) -> Option; /// Get address code at given block's state. - fn code(&self, address: &Address, state: StateOrBlock) -> Option>; + fn code(&self, address: &Address, state: StateOrBlock) -> StateResult>; /// Get address code at the latest block's state. fn latest_code(&self, address: &Address) -> Option { - self.code(address, BlockId::Latest.into()) - .expect("code will return Some if given BlockId::Latest; qed") + match self.code(address, BlockId::Latest.into()) { + StateResult::Missing => panic!("code will return Some if given BlockId::Latest; qed"), + StateResult::Some(t) => t, + } } /// Get a reference to the `BlockProvider`. diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index c0e057d84..1e4896b90 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -77,6 +77,7 @@ use client_traits::{ ScheduleInfo, StateClient, StateOrBlock, + StateResult, Tick, TransactionInfo }; @@ -1758,14 +1759,14 @@ impl BlockChainClient for Client { Self::block_hash(&chain, id) } - fn code(&self, address: &Address, state: StateOrBlock) -> Option> { + fn code(&self, address: &Address, state: StateOrBlock) -> StateResult> { let result = match state { StateOrBlock::State(s) => s.code(address).ok(), StateOrBlock::Block(id) => self.state_at(id).and_then(|s| s.code(address).ok()) }; - // Converting from `Option>>` to `Option>` - result.map(|c| c.map(|c| (&*c).clone())) + // Converting from `Option>>` to `StateResult>` + result.map_or(StateResult::Missing, |c| StateResult::Some(c.map(|c| (&*c).clone()))) } fn storage_at(&self, address: &Address, position: &H256, state: StateOrBlock) -> Option { diff --git a/ethcore/src/test_helpers/test_client.rs b/ethcore/src/test_helpers/test_client.rs index 51cbed75e..548e457aa 100644 --- a/ethcore/src/test_helpers/test_client.rs +++ b/ethcore/src/test_helpers/test_client.rs @@ -71,7 +71,7 @@ use client::{ use client_traits::{ BlockInfo, Nonce, Balance, ChainInfo, TransactionInfo, BlockChainClient, ImportBlock, AccountData, BlockChain, IoClient, BadBlocks, ScheduleInfo, StateClient, ProvingBlockChainClient, - StateOrBlock + StateOrBlock, StateResult }; use engine::Engine; use machine::executed::Executed; @@ -702,10 +702,10 @@ impl BlockChainClient for TestBlockChainClient { None } - fn code(&self, address: &Address, state: StateOrBlock) -> Option> { + fn code(&self, address: &Address, state: StateOrBlock) -> StateResult> { match state { - StateOrBlock::Block(BlockId::Latest) => Some(self.code.read().get(address).cloned()), - _ => None, + StateOrBlock::Block(BlockId::Latest) => StateResult::Some(self.code.read().get(address).cloned()), + _ => StateResult::Missing, } } diff --git a/parity/blockchain.rs b/parity/blockchain.rs index 8ca2ca381..ba8073617 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -26,7 +26,7 @@ use hash::{keccak, KECCAK_NULL_RLP}; use ethereum_types::{U256, H256, Address}; use bytes::ToPretty; use rlp::PayloadInfo; -use client_traits::{BlockChainReset, Nonce, Balance, BlockChainClient, ImportExportBlocks}; +use client_traits::{BlockChainReset, Nonce, Balance, BlockChainClient, ImportExportBlocks, StateResult}; use ethcore::{ client::{DatabaseCompactionProfile, VMType}, miner::Miner, @@ -592,7 +592,10 @@ 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.into()).unwrap_or(None).unwrap_or_else(Vec::new); + let code = match client.code(&account, at.into()) { + StateResult::Missing => Vec::new(), + StateResult::Some(t) => t.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 { diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 1e6b08847..a70c3e458 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -25,7 +25,7 @@ use ethereum_types::{Address, H64, H160, H256, U64, U256, BigEndianHash}; use parking_lot::Mutex; use account_state::state::StateInfo; -use client_traits::{BlockChainClient, StateClient, ProvingBlockChainClient, StateOrBlock}; +use client_traits::{BlockChainClient, StateClient, ProvingBlockChainClient, StateOrBlock, StateResult}; use ethash::{self, SeedHashCompute}; use ethcore::client::{Call, EngineInfo}; use ethcore::miner::{self, MinerService}; @@ -742,8 +742,8 @@ impl Eth for EthClient< try_bf!(check_known(&*self.client, num.clone())); 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()), + StateResult::Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)), + StateResult::Missing => Err(errors::state_pruned()), }; Box::new(future::done(res))