Allow default block parameter to be blockHash (#10932)
* allow default block parameter to be blockHash * requireCanonical * block check takes precedence over canon check
This commit is contained in:
parent
13ccb9f827
commit
72279856cd
@ -1759,6 +1759,10 @@ impl BlockChainClient for Client {
|
|||||||
self.config.spec_name.clone()
|
self.config.spec_name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn chain(&self) -> Arc<BlockProvider> {
|
||||||
|
self.chain.read().clone()
|
||||||
|
}
|
||||||
|
|
||||||
fn set_spec_name(&self, new_spec_name: String) -> Result<(), ()> {
|
fn set_spec_name(&self, new_spec_name: String) -> Result<(), ()> {
|
||||||
trace!(target: "mode", "Client::set_spec_name({:?})", new_spec_name);
|
trace!(target: "mode", "Client::set_spec_name({:?})", new_spec_name);
|
||||||
if !self.enabled.load(AtomicOrdering::Relaxed) {
|
if !self.enabled.load(AtomicOrdering::Relaxed) {
|
||||||
|
@ -20,6 +20,7 @@ use std::str::FromStr;
|
|||||||
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrder};
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrder};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::collections::{HashMap, BTreeMap};
|
use std::collections::{HashMap, BTreeMap};
|
||||||
|
use blockchain::BlockProvider;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use blockchain::{TreeRoute, BlockReceipts};
|
use blockchain::{TreeRoute, BlockReceipts};
|
||||||
@ -703,6 +704,10 @@ impl BlockChainClient for TestBlockChainClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn chain(&self) -> Arc<BlockProvider> {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
fn list_accounts(&self, _id: BlockId, _after: Option<&Address>, _count: u64) -> Option<Vec<Address>> {
|
fn list_accounts(&self, _id: BlockId, _after: Option<&Address>, _count: u64) -> Option<Vec<Address>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use blockchain::{BlockReceipts, TreeRoute};
|
use blockchain::{BlockReceipts, TreeRoute, BlockProvider};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use call_contract::{CallContract, RegistryInfo};
|
use call_contract::{CallContract, RegistryInfo};
|
||||||
use ethcore_miner::pool::VerifiedTransaction;
|
use ethcore_miner::pool::VerifiedTransaction;
|
||||||
@ -233,6 +233,8 @@ pub trait BlockChainClient : Sync + Send + AccountData + BlockChain + CallContra
|
|||||||
.expect("code will return Some if given BlockId::Latest; qed")
|
.expect("code will return Some if given BlockId::Latest; qed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn chain(&self) -> Arc<BlockProvider>;
|
||||||
|
|
||||||
/// Get block queue information.
|
/// Get block queue information.
|
||||||
fn queue_info(&self) -> BlockQueueInfo;
|
fn queue_info(&self) -> BlockQueueInfo;
|
||||||
|
|
||||||
|
@ -609,3 +609,13 @@ pub fn require_experimental(allow_experimental_rpcs: bool, eip: &str) -> Result<
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns an error for when require_canonical was specified and
|
||||||
|
pub fn invalid_input() -> Error {
|
||||||
|
Error {
|
||||||
|
// UNSUPPORTED_REQUEST shares the same error code for EIP-1898
|
||||||
|
code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST),
|
||||||
|
message: "Invalid input".into(),
|
||||||
|
data: None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -263,6 +263,7 @@ where
|
|||||||
// (they don't have state) we can safely fallback to `Latest`.
|
// (they don't have state) we can safely fallback to `Latest`.
|
||||||
let id = match num.unwrap_or_default() {
|
let id = match num.unwrap_or_default() {
|
||||||
BlockNumber::Num(n) => BlockId::Number(n),
|
BlockNumber::Num(n) => BlockId::Number(n),
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
BlockNumber::Pending => {
|
BlockNumber::Pending => {
|
||||||
|
@ -241,6 +241,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S
|
|||||||
|
|
||||||
BlockNumberOrId::Number(num) => {
|
BlockNumberOrId::Number(num) => {
|
||||||
let id = match num {
|
let id = match num {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Num(n) => BlockId::Number(n),
|
BlockNumber::Num(n) => BlockId::Number(n),
|
||||||
@ -433,10 +434,10 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> EthClient<C, SN, S
|
|||||||
|
|
||||||
fn get_state(&self, number: BlockNumber) -> StateOrBlock {
|
fn get_state(&self, number: BlockNumber) -> StateOrBlock {
|
||||||
match number {
|
match number {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash).into(),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num).into(),
|
BlockNumber::Num(num) => BlockId::Number(num).into(),
|
||||||
BlockNumber::Earliest => BlockId::Earliest.into(),
|
BlockNumber::Earliest => BlockId::Earliest.into(),
|
||||||
BlockNumber::Latest => BlockId::Latest.into(),
|
BlockNumber::Latest => BlockId::Latest.into(),
|
||||||
|
|
||||||
BlockNumber::Pending => {
|
BlockNumber::Pending => {
|
||||||
let info = self.client.chain_info();
|
let info = self.client.chain_info();
|
||||||
|
|
||||||
@ -472,10 +473,22 @@ fn check_known<C>(client: &C, number: BlockNumber) -> Result<()> where C: BlockC
|
|||||||
|
|
||||||
let id = match number {
|
let id = match number {
|
||||||
BlockNumber::Pending => return Ok(()),
|
BlockNumber::Pending => return Ok(()),
|
||||||
|
|
||||||
BlockNumber::Num(n) => BlockId::Number(n),
|
BlockNumber::Num(n) => BlockId::Number(n),
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
|
BlockNumber::Hash { hash, require_canonical } => {
|
||||||
|
// block check takes precedence over canon check.
|
||||||
|
match client.block_status(BlockId::Hash(hash.clone())) {
|
||||||
|
BlockStatus::InChain => {},
|
||||||
|
_ => return Err(errors::unknown_block()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if require_canonical && !client.chain().is_canon(&hash) {
|
||||||
|
return Err(errors::invalid_input())
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match client.block_status(id) {
|
match client.block_status(id) {
|
||||||
@ -589,6 +602,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
|||||||
|
|
||||||
let num = num.unwrap_or_default();
|
let num = num.unwrap_or_default();
|
||||||
let id = match num {
|
let id = match num {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(n) => BlockId::Number(n),
|
BlockNumber::Num(n) => BlockId::Number(n),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
@ -762,6 +776,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
|||||||
|
|
||||||
fn transaction_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<Transaction>> {
|
fn transaction_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<Transaction>> {
|
||||||
let block_id = match num {
|
let block_id = match num {
|
||||||
|
BlockNumber::Hash { hash, .. } => PendingOrBlock::Block(BlockId::Hash(hash)),
|
||||||
BlockNumber::Latest => PendingOrBlock::Block(BlockId::Latest),
|
BlockNumber::Latest => PendingOrBlock::Block(BlockId::Latest),
|
||||||
BlockNumber::Earliest => PendingOrBlock::Block(BlockId::Earliest),
|
BlockNumber::Earliest => PendingOrBlock::Block(BlockId::Earliest),
|
||||||
BlockNumber::Num(num) => PendingOrBlock::Block(BlockId::Number(num)),
|
BlockNumber::Num(num) => PendingOrBlock::Block(BlockId::Number(num)),
|
||||||
@ -798,6 +813,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
|||||||
|
|
||||||
fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<RichBlock>> {
|
fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> BoxFuture<Option<RichBlock>> {
|
||||||
let id = match num {
|
let id = match num {
|
||||||
|
BlockNumber::Hash { hash, .. } => PendingUncleId { id: PendingOrBlock::Block(BlockId::Hash(hash)), position: index.value() },
|
||||||
BlockNumber::Latest => PendingUncleId { id: PendingOrBlock::Block(BlockId::Latest), position: index.value() },
|
BlockNumber::Latest => PendingUncleId { id: PendingOrBlock::Block(BlockId::Latest), position: index.value() },
|
||||||
BlockNumber::Earliest => PendingUncleId { id: PendingOrBlock::Block(BlockId::Earliest), position: index.value() },
|
BlockNumber::Earliest => PendingUncleId { id: PendingOrBlock::Block(BlockId::Earliest), position: index.value() },
|
||||||
BlockNumber::Num(num) => PendingUncleId { id: PendingOrBlock::Block(BlockId::Number(num)), position: index.value() },
|
BlockNumber::Num(num) => PendingUncleId { id: PendingOrBlock::Block(BlockId::Number(num)), position: index.value() },
|
||||||
@ -914,6 +930,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
|||||||
let signed = try_bf!(fake_sign::sign_call(request));
|
let signed = try_bf!(fake_sign::sign_call(request));
|
||||||
|
|
||||||
let num = num.unwrap_or_default();
|
let num = num.unwrap_or_default();
|
||||||
|
try_bf!(check_known(&*self.client, num.clone()));
|
||||||
|
|
||||||
let (mut state, header) = if num == BlockNumber::Pending {
|
let (mut state, header) = if num == BlockNumber::Pending {
|
||||||
let info = self.client.chain_info();
|
let info = self.client.chain_info();
|
||||||
@ -923,6 +940,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
|||||||
(state, header)
|
(state, header)
|
||||||
} else {
|
} else {
|
||||||
let id = match num {
|
let id = match num {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
@ -964,6 +982,7 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM, T: StateInfo + 'static> Eth for EthClient<
|
|||||||
(state, header)
|
(state, header)
|
||||||
} else {
|
} else {
|
||||||
let id = match num {
|
let id = match num {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
|
@ -350,6 +350,7 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
|
|||||||
(header.encoded(), None)
|
(header.encoded(), None)
|
||||||
} else {
|
} else {
|
||||||
let id = match number {
|
let id = match number {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
@ -381,6 +382,7 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
|
|||||||
.collect()
|
.collect()
|
||||||
))
|
))
|
||||||
},
|
},
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
@ -412,6 +414,7 @@ impl<C, M, U, S> Parity for ParityClient<C, M, U> where
|
|||||||
(state, header)
|
(state, header)
|
||||||
} else {
|
} else {
|
||||||
let id = match num {
|
let id = match num {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
|
@ -95,6 +95,7 @@ impl<C, S> Traces for TracesClient<C> where
|
|||||||
let signed = fake_sign::sign_call(request)?;
|
let signed = fake_sign::sign_call(request)?;
|
||||||
|
|
||||||
let id = match block {
|
let id = match block {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
@ -122,6 +123,7 @@ impl<C, S> Traces for TracesClient<C> where
|
|||||||
.collect::<Result<Vec<_>>>()?;
|
.collect::<Result<Vec<_>>>()?;
|
||||||
|
|
||||||
let id = match block {
|
let id = match block {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
@ -144,6 +146,7 @@ impl<C, S> Traces for TracesClient<C> where
|
|||||||
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
|
let signed = SignedTransaction::new(tx).map_err(errors::transaction)?;
|
||||||
|
|
||||||
let id = match block {
|
let id = match block {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
@ -167,6 +170,7 @@ impl<C, S> Traces for TracesClient<C> where
|
|||||||
|
|
||||||
fn replay_block_transactions(&self, block_number: BlockNumber, flags: TraceOptions) -> Result<Vec<TraceResultsWithTransactionHash>> {
|
fn replay_block_transactions(&self, block_number: BlockNumber, flags: TraceOptions) -> Result<Vec<TraceResultsWithTransactionHash>> {
|
||||||
let id = match block_number {
|
let id = match block_number {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
|
@ -16,12 +16,20 @@
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
use serde::de::{Error, Visitor};
|
use serde::de::{Error, Visitor, MapAccess};
|
||||||
use ethcore::client::BlockId;
|
use ethcore::client::BlockId;
|
||||||
|
use ethereum_types::H256;
|
||||||
|
|
||||||
/// Represents rpc api block number param.
|
/// Represents rpc api block number param.
|
||||||
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
|
#[derive(Debug, PartialEq, Clone, Hash, Eq)]
|
||||||
pub enum BlockNumber {
|
pub enum BlockNumber {
|
||||||
|
/// Hash
|
||||||
|
Hash {
|
||||||
|
/// block hash
|
||||||
|
hash: H256,
|
||||||
|
/// only return blocks part of the canon chain
|
||||||
|
require_canonical: bool,
|
||||||
|
},
|
||||||
/// Number
|
/// Number
|
||||||
Num(u64),
|
Num(u64),
|
||||||
/// Latest block
|
/// Latest block
|
||||||
@ -68,6 +76,7 @@ impl LightBlockNumber for BlockNumber {
|
|||||||
// Since light clients don't produce pending blocks
|
// Since light clients don't produce pending blocks
|
||||||
// (they don't have state) we can safely fallback to `Latest`.
|
// (they don't have state) we can safely fallback to `Latest`.
|
||||||
match self {
|
match self {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(n) => BlockId::Number(n),
|
BlockNumber::Num(n) => BlockId::Number(n),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
@ -82,6 +91,9 @@ impl LightBlockNumber for BlockNumber {
|
|||||||
impl Serialize for BlockNumber {
|
impl Serialize for BlockNumber {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
|
||||||
match *self {
|
match *self {
|
||||||
|
BlockNumber::Hash{ hash, require_canonical } => serializer.serialize_str(
|
||||||
|
&format!("{{ 'hash': '{}', 'requireCanonical': '{}' }}", hash, require_canonical)
|
||||||
|
),
|
||||||
BlockNumber::Num(ref x) => serializer.serialize_str(&format!("0x{:x}", x)),
|
BlockNumber::Num(ref x) => serializer.serialize_str(&format!("0x{:x}", x)),
|
||||||
BlockNumber::Latest => serializer.serialize_str("latest"),
|
BlockNumber::Latest => serializer.serialize_str("latest"),
|
||||||
BlockNumber::Earliest => serializer.serialize_str("earliest"),
|
BlockNumber::Earliest => serializer.serialize_str("earliest"),
|
||||||
@ -99,6 +111,54 @@ impl<'a> Visitor<'a> for BlockNumberVisitor {
|
|||||||
write!(formatter, "a block number or 'latest', 'earliest' or 'pending'")
|
write!(formatter, "a block number or 'latest', 'earliest' or 'pending'")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error> where V: MapAccess<'a> {
|
||||||
|
let (mut require_canonical, mut block_number, mut block_hash) = (false, None::<u64>, None::<H256>);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let key_str: Option<String> = visitor.next_key()?;
|
||||||
|
|
||||||
|
match key_str {
|
||||||
|
Some(key) => match key.as_str() {
|
||||||
|
"blockNumber" => {
|
||||||
|
let value: String = visitor.next_value()?;
|
||||||
|
if value.starts_with("0x") {
|
||||||
|
let number = u64::from_str_radix(&value[2..], 16).map_err(|e| {
|
||||||
|
Error::custom(format!("Invalid block number: {}", e))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
block_number = Some(number);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return Err(Error::custom("Invalid block number: missing 0x prefix".to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"blockHash" => {
|
||||||
|
block_hash = Some(visitor.next_value()?);
|
||||||
|
}
|
||||||
|
"requireCanonical" => {
|
||||||
|
require_canonical = visitor.next_value()?;
|
||||||
|
}
|
||||||
|
key => {
|
||||||
|
return Err(Error::custom(format!("Unknown key: {}", key)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(number) = block_number {
|
||||||
|
return Ok(BlockNumber::Num(number))
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(hash) = block_hash {
|
||||||
|
return Ok(BlockNumber::Hash { hash, require_canonical })
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(Error::custom("Invalid input"))
|
||||||
|
}
|
||||||
|
|
||||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: Error {
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: Error {
|
||||||
match value {
|
match value {
|
||||||
"latest" => Ok(BlockNumber::Latest),
|
"latest" => Ok(BlockNumber::Latest),
|
||||||
@ -107,7 +167,9 @@ impl<'a> Visitor<'a> for BlockNumberVisitor {
|
|||||||
_ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|e| {
|
_ if value.starts_with("0x") => u64::from_str_radix(&value[2..], 16).map(BlockNumber::Num).map_err(|e| {
|
||||||
Error::custom(format!("Invalid block number: {}", e))
|
Error::custom(format!("Invalid block number: {}", e))
|
||||||
}),
|
}),
|
||||||
_ => Err(Error::custom("Invalid block number: missing 0x prefix".to_string())),
|
_ => {
|
||||||
|
Err(Error::custom("Invalid block number: missing 0x prefix".to_string()))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,10 +181,10 @@ impl<'a> Visitor<'a> for BlockNumberVisitor {
|
|||||||
/// Converts `BlockNumber` to `BlockId`, panics on `BlockNumber::Pending`
|
/// Converts `BlockNumber` to `BlockId`, panics on `BlockNumber::Pending`
|
||||||
pub fn block_number_to_id(number: BlockNumber) -> BlockId {
|
pub fn block_number_to_id(number: BlockNumber) -> BlockId {
|
||||||
match number {
|
match number {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(num) => BlockId::Number(num),
|
BlockNumber::Num(num) => BlockId::Number(num),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
|
|
||||||
BlockNumber::Pending => panic!("`BlockNumber::Pending` should be handled manually")
|
BlockNumber::Pending => panic!("`BlockNumber::Pending` should be handled manually")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,19 +193,40 @@ pub fn block_number_to_id(number: BlockNumber) -> BlockId {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use ethcore::client::BlockId;
|
use ethcore::client::BlockId;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::str::FromStr;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn block_number_deserialization() {
|
fn block_number_deserialization() {
|
||||||
let s = r#"["0xa", "latest", "earliest", "pending"]"#;
|
let s = r#"[
|
||||||
|
"0xa",
|
||||||
|
"latest",
|
||||||
|
"earliest",
|
||||||
|
"pending",
|
||||||
|
{"blockNumber": "0xa"},
|
||||||
|
{"blockHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"},
|
||||||
|
{"blockHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", "requireCanonical": true}
|
||||||
|
]"#;
|
||||||
let deserialized: Vec<BlockNumber> = serde_json::from_str(s).unwrap();
|
let deserialized: Vec<BlockNumber> = serde_json::from_str(s).unwrap();
|
||||||
assert_eq!(deserialized, vec![BlockNumber::Num(10), BlockNumber::Latest, BlockNumber::Earliest, BlockNumber::Pending])
|
|
||||||
|
assert_eq!(
|
||||||
|
deserialized,
|
||||||
|
vec![
|
||||||
|
BlockNumber::Num(10),
|
||||||
|
BlockNumber::Latest,
|
||||||
|
BlockNumber::Earliest,
|
||||||
|
BlockNumber::Pending,
|
||||||
|
BlockNumber::Num(10),
|
||||||
|
BlockNumber::Hash { hash: H256::from_str("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").unwrap(), require_canonical: false },
|
||||||
|
BlockNumber::Hash { hash: H256::from_str("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").unwrap(), require_canonical: true }
|
||||||
|
]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_not_deserialize_decimal() {
|
fn should_not_deserialize() {
|
||||||
let s = r#""10""#;
|
let s = r#"[{}, "10"]"#;
|
||||||
assert!(serde_json::from_str::<BlockNumber>(s).is_err());
|
assert!(serde_json::from_str::<Vec<BlockNumber>>(s).is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -82,6 +82,7 @@ impl Filter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let num_to_id = |num| match num {
|
let num_to_id = |num| match num {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(n) => BlockId::Number(n),
|
BlockNumber::Num(n) => BlockId::Number(n),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest,
|
BlockNumber::Latest | BlockNumber::Pending => BlockId::Latest,
|
||||||
|
@ -43,6 +43,7 @@ pub struct TraceFilter {
|
|||||||
impl Into<client::TraceFilter> for TraceFilter {
|
impl Into<client::TraceFilter> for TraceFilter {
|
||||||
fn into(self) -> client::TraceFilter {
|
fn into(self) -> client::TraceFilter {
|
||||||
let num_to_id = |num| match num {
|
let num_to_id = |num| match num {
|
||||||
|
BlockNumber::Hash { hash, .. } => BlockId::Hash(hash),
|
||||||
BlockNumber::Num(n) => BlockId::Number(n),
|
BlockNumber::Num(n) => BlockId::Number(n),
|
||||||
BlockNumber::Earliest => BlockId::Earliest,
|
BlockNumber::Earliest => BlockId::Earliest,
|
||||||
BlockNumber::Latest => BlockId::Latest,
|
BlockNumber::Latest => BlockId::Latest,
|
||||||
|
Loading…
Reference in New Issue
Block a user