diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 00c8dd8de..c46f477b1 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -619,7 +619,8 @@ impl Client { /// 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. + /// Otherwise, this can fail (but may not) if the DB prunes state or the block + /// is unknown. pub fn state_at(&self, id: BlockId) -> Option { // fast path for latest state. match id.clone() { diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index e482b418a..075f3f11c 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -523,7 +523,8 @@ impl BlockChainClient for TestBlockChainClient { match id { 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, - _ => BlockStatus::Unknown + BlockId::Latest | BlockId::Pending | BlockId::Earliest => BlockStatus::InChain, + _ => BlockStatus::Unknown, } } diff --git a/ethcore/src/client/traits.rs b/ethcore/src/client/traits.rs index caba647d1..2d7d882ee 100644 --- a/ethcore/src/client/traits.rs +++ b/ethcore/src/client/traits.rs @@ -277,7 +277,7 @@ pub trait BlockChainClient : Sync + Send { /// Get the address of the registry itself. fn registrar_address(&self) -> Option
; - /// Get the address of a particular blockchain service, if available. + /// Get the address of a particular blockchain service, if available. fn registry_address(&self, name: String) -> Option
; } diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 83b3b0c58..80a0dab9a 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -290,3 +290,11 @@ pub fn from_call_error(error: CallError) -> Error { CallError::TransactionNotFound => internal("{}, this should not be the case with eth_call, most likely a bug.", CallError::TransactionNotFound), } } + +pub fn unknown_block() -> Error { + Error { + code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), + message: "Unknown block number".into(), + data: None, + } +} diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 491bdde10..178377692 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -238,6 +238,15 @@ pub fn pending_logs(miner: &M, best_block: EthBlockNumber, filter: &EthcoreFi result } +fn check_known(client: &C, number: BlockNumber) -> Result<(), Error> where C: MiningBlockChainClient { + use ethcore::block_status::BlockStatus; + + match client.block_status(number.into()) { + BlockStatus::InChain => Ok(()), + _ => Err(errors::unknown_block()), + } +} + const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6. impl EthClient where @@ -359,9 +368,14 @@ impl Eth for EthClient where let address = address.into(); match num.0 { BlockNumber::Pending => Ok(take_weak!(self.miner).balance(&*take_weak!(self.client), &address).into()), - id => match take_weak!(self.client).balance(&address, id.into()) { - Some(balance) => Ok(balance.into()), - None => Err(errors::state_pruned()), + id => { + let client = take_weak!(self.client); + + check_known(&*client, id.clone())?; + match client.balance(&address, id.into()) { + Some(balance) => Ok(balance.into()), + None => Err(errors::state_pruned()), + } } } } @@ -372,9 +386,14 @@ impl Eth for EthClient where let position: U256 = RpcU256::into(pos); match num.0 { BlockNumber::Pending => Ok(take_weak!(self.miner).storage_at(&*take_weak!(self.client), &address, &H256::from(position)).into()), - id => match take_weak!(self.client).storage_at(&address, &H256::from(position), id.into()) { - Some(s) => Ok(s.into()), - None => Err(errors::state_pruned()), + id => { + let client = take_weak!(self.client); + + check_known(&*client, id.clone())?; + match client.storage_at(&address, &H256::from(position), id.into()) { + Some(s) => Ok(s.into()), + None => Err(errors::state_pruned()), + } } } } @@ -385,9 +404,14 @@ impl Eth for EthClient where let address: Address = RpcH160::into(address); match num.0 { BlockNumber::Pending => Ok(take_weak!(self.miner).nonce(&*take_weak!(self.client), &address).into()), - id => match take_weak!(self.client).nonce(&address, id.into()) { - Some(nonce) => Ok(nonce.into()), - None => Err(errors::state_pruned()), + id => { + let client = take_weak!(self.client); + + check_known(&*client, id.clone())?; + match client.nonce(&address, id.into()) { + Some(nonce) => Ok(nonce.into()), + None => Err(errors::state_pruned()), + } } } } @@ -441,10 +465,15 @@ impl Eth for EthClient where let address: Address = RpcH160::into(address); match num.0 { BlockNumber::Pending => Ok(take_weak!(self.miner).code(&*take_weak!(self.client), &address).map_or_else(Bytes::default, Bytes::new)), - _ => match take_weak!(self.client).code(&address, num.0.into()) { - Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)), - None => Err(errors::state_pruned()), - }, + id => { + let client = take_weak!(self.client); + + check_known(&*client, id.clone())?; + match client.code(&address, id.into()) { + Some(code) => Ok(code.map_or_else(Bytes::default, Bytes::new)), + None => Err(errors::state_pruned()), + } + } } }