870 lines
27 KiB
Rust
870 lines
27 KiB
Rust
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
|
// This file is part of Parity Ethereum.
|
|
|
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use ethereum_types::{Address, U256};
|
|
use serde::de::{Deserialize, Deserializer, Error, MapAccess, Visitor};
|
|
use std::fmt;
|
|
use std::marker::PhantomData;
|
|
|
|
/// This structure provides filtering options for the pending transactions RPC API call
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
pub struct FilterOptions {
|
|
/// Contains the operator to filter the from value of the transaction
|
|
pub from: FilterOperator<Address>,
|
|
/// Contains the operator to filter the to value of the transaction
|
|
pub to: FilterOperator<Option<Address>>,
|
|
/// Contains the operator to filter the gas value of the transaction
|
|
pub gas: FilterOperator<U256>,
|
|
/// Contains the operator to filter the gas price value of the transaction
|
|
pub gas_price: FilterOperator<U256>,
|
|
/// Contains the operator to filter the transaction value
|
|
pub value: FilterOperator<U256>,
|
|
/// Contains the operator to filter the nonce value of the transaction
|
|
pub nonce: FilterOperator<U256>,
|
|
}
|
|
|
|
impl Default for FilterOptions {
|
|
fn default() -> Self {
|
|
FilterOptions {
|
|
from: FilterOperator::Any,
|
|
to: FilterOperator::Any,
|
|
gas: FilterOperator::Any,
|
|
gas_price: FilterOperator::Any,
|
|
value: FilterOperator::Any,
|
|
nonce: FilterOperator::Any,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The highly generic use of implementing Deserialize for FilterOperator
|
|
/// will result in a compiler error if the type FilterOperator::Eq(None)
|
|
/// gets returned explicitly. Therefore this Wrapper will be used for
|
|
/// deserialization, directly identifying the contract creation.
|
|
enum Wrapper<T> {
|
|
O(FilterOperator<T>),
|
|
CC, // Contract Creation
|
|
}
|
|
|
|
/// Available operators for filtering options.
|
|
/// The `from` filter only accepts Any and Eq(Address)
|
|
/// The `to` filter only accepts Any, Eq(Address) and Eq(None) for contract creation.
|
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
pub enum FilterOperator<T> {
|
|
Any,
|
|
Eq(T),
|
|
GreaterThan(T),
|
|
LessThan(T),
|
|
}
|
|
|
|
/// Since there are multiple operators which are not supported equally by all filters,
|
|
/// this trait will validate each of those operators. The corresponding method is called
|
|
/// inside the `Deserialize` -> `Visitor` implementation for FilterOperator. In case new
|
|
/// operators get introduced, a whitelist instead of a blacklist is used.
|
|
///
|
|
/// The `from` filter validates with `validate_from`
|
|
/// The `to` filter validates with `validate_from`
|
|
/// All other filters such as gas and price validate with `validate_value`
|
|
trait Validate<'de, T, M: MapAccess<'de>> {
|
|
fn validate_from(&mut self) -> Result<FilterOperator<T>, M::Error>;
|
|
fn validate_to(&mut self) -> Result<FilterOperator<Option<Address>>, M::Error>;
|
|
fn validate_value(&mut self) -> Result<FilterOperator<T>, M::Error>;
|
|
}
|
|
|
|
impl<'de, T, M> Validate<'de, T, M> for M
|
|
where T: Deserialize<'de>, M: MapAccess<'de>
|
|
{
|
|
fn validate_from(&mut self) -> Result<FilterOperator<T>, M::Error> {
|
|
use self::Wrapper as W;
|
|
use self::FilterOperator::*;
|
|
let wrapper = self.next_value()?;
|
|
match wrapper {
|
|
W::O(val) => {
|
|
match val {
|
|
Any | Eq(_) => Ok(val),
|
|
_ => {
|
|
Err(M::Error::custom(
|
|
"the `from` filter only supports the `eq` operator",
|
|
))
|
|
}
|
|
}
|
|
},
|
|
W::CC => {
|
|
Err(M::Error::custom(
|
|
"the `from` filter only supports the `eq` operator",
|
|
))
|
|
}
|
|
}
|
|
}
|
|
fn validate_to(&mut self) -> Result<FilterOperator<Option<Address>>, M::Error> {
|
|
use self::Wrapper as W;
|
|
use self::FilterOperator::*;
|
|
let wrapper = self.next_value()?;
|
|
match wrapper {
|
|
W::O(val) => {
|
|
match val {
|
|
Any => Ok(Any),
|
|
Eq(address) => Ok(Eq(Some(address))),
|
|
_ => {
|
|
Err(M::Error::custom(
|
|
"the `to` filter only supports the `eq` or `action` operator",
|
|
))
|
|
}
|
|
}
|
|
},
|
|
W::CC => Ok(FilterOperator::Eq(None)),
|
|
}
|
|
}
|
|
fn validate_value(&mut self) -> Result<FilterOperator<T>, M::Error> {
|
|
use self::Wrapper as W;
|
|
let wrapper = self.next_value()?;
|
|
match wrapper {
|
|
W::O(val) => Ok(val),
|
|
W::CC => {
|
|
Err(M::Error::custom(
|
|
"the operator `action` is only supported by the `to` filter",
|
|
))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for FilterOptions {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct FilterOptionsVisitor;
|
|
impl<'de> Visitor<'de> for FilterOptionsVisitor {
|
|
type Value = FilterOptions;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
// "This Visitor expects to receive ..."
|
|
formatter.write_str("a map with one valid filter such as `from`, `to`, `gas`, `gas_price`, `value` or `nonce`")
|
|
}
|
|
|
|
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
|
where
|
|
M: MapAccess<'de>,
|
|
{
|
|
let mut filter = FilterOptions::default();
|
|
while let Some(key) = map.next_key::<String>()? {
|
|
match key.as_str() {
|
|
"from" => {
|
|
filter.from = map.validate_from()?;
|
|
},
|
|
"to" => {
|
|
// Compiler cannot infer type, so set one (nothing specific for this method)
|
|
filter.to = Validate::<(), _>::validate_to(&mut map)?;
|
|
},
|
|
"gas" => {
|
|
filter.gas = map.validate_value()?;
|
|
},
|
|
"gas_price" => {
|
|
filter.gas_price = map.validate_value()?;
|
|
},
|
|
"value" => {
|
|
filter.value = map.validate_value()?;
|
|
},
|
|
"nonce" => {
|
|
filter.nonce = map.validate_value()?;
|
|
},
|
|
unknown => {
|
|
return Err(M::Error::unknown_field(
|
|
unknown,
|
|
&["from", "to", "gas", "gas_price", "value", "nonce"],
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(filter)
|
|
}
|
|
}
|
|
|
|
impl<'de, T: Deserialize<'de>> Deserialize<'de> for Wrapper<T> {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
struct WrapperVisitor<T> {
|
|
data: PhantomData<T>,
|
|
};
|
|
impl<'de, T: Deserialize<'de>> Visitor<'de> for WrapperVisitor<T> {
|
|
type Value = Wrapper<T>;
|
|
|
|
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
|
// "This Visitor expects to receive ..."
|
|
formatter.write_str(
|
|
"a map with one valid operator such as `eq`, `gt` or `lt`. \
|
|
The to filter can also contain `action`",
|
|
)
|
|
}
|
|
|
|
fn visit_map<M>(self, mut map: M) -> Result<Self::Value, M::Error>
|
|
where
|
|
M: MapAccess<'de>,
|
|
{
|
|
use self::Wrapper as W;
|
|
let mut counter = 0;
|
|
let mut f_op = Wrapper::O(FilterOperator::Any);
|
|
|
|
while let Some(key) = map.next_key::<String>()? {
|
|
match key.as_str() {
|
|
"eq" => f_op = W::O(FilterOperator::Eq(map.next_value()?)),
|
|
"gt" => f_op = W::O(FilterOperator::GreaterThan(map.next_value()?)),
|
|
"lt" => f_op = W::O(FilterOperator::LessThan(map.next_value()?)),
|
|
"action" => {
|
|
match map.next_value()? {
|
|
"contract_creation" => {
|
|
f_op = W::CC;
|
|
},
|
|
_ => {
|
|
return Err(M::Error::custom(
|
|
"`action` only supports the value `contract_creation`",
|
|
))
|
|
}
|
|
}
|
|
}
|
|
unknown => {
|
|
// skip mentioning `action` since it's a special/rare
|
|
// case and might confuse the usage with other filters.
|
|
return Err(M::Error::unknown_field(unknown, &["eq", "gt", "lt"]));
|
|
}
|
|
}
|
|
|
|
counter += 1;
|
|
}
|
|
|
|
// Good practices ensured: only one operator per filter field is allowed.
|
|
// In case there is more than just one operator, this method must still process
|
|
// all of them, otherwise serde returns an error mentioning a trailing comma issue
|
|
// (even on valid JSON), which is misleading to the user of this software.
|
|
if counter > 1 {
|
|
return Err(M::Error::custom(
|
|
"only one operator per filter type allowed",
|
|
));
|
|
}
|
|
|
|
Ok(f_op)
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_map(WrapperVisitor { data: PhantomData })
|
|
}
|
|
}
|
|
|
|
deserializer.deserialize_map(FilterOptionsVisitor)
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use ethereum_types::{Address, U256};
|
|
use serde_json;
|
|
use super::*;
|
|
use std::str::FromStr;
|
|
|
|
#[test]
|
|
fn valid_defaults() {
|
|
let default = FilterOptions::default();
|
|
assert_eq!(default.from, FilterOperator::Any);
|
|
assert_eq!(default.to, FilterOperator::Any);
|
|
assert_eq!(default.gas, FilterOperator::Any);
|
|
assert_eq!(default.gas_price, FilterOperator::Any);
|
|
assert_eq!(default.value, FilterOperator::Any);
|
|
assert_eq!(default.nonce, FilterOperator::Any);
|
|
|
|
let json = r#"{}"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, default);
|
|
}
|
|
|
|
#[test]
|
|
fn valid_full_deserialization() {
|
|
let json = r#"
|
|
{
|
|
"from": {
|
|
"eq": "0x5f3dffcf347944d3739b0805c934d86c8621997f"
|
|
},
|
|
"to": {
|
|
"eq": "0xe8b2d01ffa0a15736b2370b6e5064f9702c891b6"
|
|
},
|
|
"gas": {
|
|
"eq": "0x493e0"
|
|
},
|
|
"gas_price": {
|
|
"eq": "0x12a05f200"
|
|
},
|
|
"value": {
|
|
"eq": "0x0"
|
|
},
|
|
"nonce": {
|
|
"eq": "0x577"
|
|
}
|
|
}
|
|
"#;
|
|
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
from: FilterOperator::Eq(Address::from_str("5f3dffcf347944d3739b0805c934d86c8621997f").unwrap()),
|
|
to: FilterOperator::Eq(Some(Address::from_str("e8b2d01ffa0a15736b2370b6e5064f9702c891b6").unwrap())),
|
|
gas: FilterOperator::Eq(U256::from(300_000)),
|
|
gas_price: FilterOperator::Eq(U256::from(5_000_000_000 as i64)),
|
|
value: FilterOperator::Eq(U256::from(0)),
|
|
nonce: FilterOperator::Eq(U256::from(1399)),
|
|
})
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_full_deserialization() {
|
|
// Invalid filter type `zyx`
|
|
let json = r#"
|
|
{
|
|
"from": {
|
|
"eq": "0x5f3dffcf347944d3739b0805c934d86c8621997f"
|
|
},
|
|
"to": {
|
|
"eq": "0xe8b2d01ffa0a15736b2370b6e5064f9702c891b6"
|
|
},
|
|
"zyx": {
|
|
"eq": "0x493e0"
|
|
},
|
|
"gas_price": {
|
|
"eq": "0x12a05f200"
|
|
},
|
|
"value": {
|
|
"eq": "0x0"
|
|
},
|
|
"nonce": {
|
|
"eq": "0x577"
|
|
}
|
|
}
|
|
"#;
|
|
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err())
|
|
}
|
|
|
|
#[test]
|
|
fn valid_from_operators() {
|
|
// Only one valid operator for from
|
|
let json = r#"
|
|
{
|
|
"from": {
|
|
"eq": "0x5f3dffcf347944d3739b0805c934d86c8621997f"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
from: FilterOperator::Eq(Address::from_str("5f3dffcf347944d3739b0805c934d86c8621997f").unwrap()),
|
|
..default
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_from_operators() {
|
|
// Multiple operators are invalid
|
|
let json = r#"
|
|
{
|
|
"from": {
|
|
"eq": "0x5f3dffcf347944d3739b0805c934d86c8621997f",
|
|
"lt": "0x407d73d8a49eeb85d32cf465507dd71d507100c1"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Gt
|
|
let json = r#"
|
|
{
|
|
"from": {
|
|
"gt": "0x5f3dffcf347944d3739b0805c934d86c8621997f"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Lt
|
|
let json = r#"
|
|
{
|
|
"from": {
|
|
"lt": "0x5f3dffcf347944d3739b0805c934d86c8621997f"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Action
|
|
let json = r#"
|
|
{
|
|
"from": {
|
|
"action": "contract_creation"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Unknown operator
|
|
let json = r#"
|
|
{
|
|
"from": {
|
|
"abc": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn valid_to_operators() {
|
|
// Only two valid operator for to
|
|
// Eq
|
|
let json = r#"
|
|
{
|
|
"to": {
|
|
"eq": "0xe8b2d01ffa0a15736b2370b6e5064f9702c891b6"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
to: FilterOperator::Eq(Some(Address::from_str("e8b2d01ffa0a15736b2370b6e5064f9702c891b6").unwrap())),
|
|
..default.clone()
|
|
});
|
|
|
|
// Action
|
|
let json = r#"
|
|
{
|
|
"to": {
|
|
"action": "contract_creation"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
to: FilterOperator::Eq(None),
|
|
..default
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_to_operators() {
|
|
// Multiple operators are invalid
|
|
let json = r#"
|
|
{
|
|
"to": {
|
|
"eq": "0xe8b2d01ffa0a15736b2370b6e5064f9702c891b6",
|
|
"action": "contract_creation"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Gt
|
|
let json = r#"
|
|
{
|
|
"to": {
|
|
"gt": "0xe8b2d01ffa0a15736b2370b6e5064f9702c891b6"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Lt
|
|
let json = r#"
|
|
{
|
|
"to": {
|
|
"lt": "0xe8b2d01ffa0a15736b2370b6e5064f9702c891b6"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Action (invalid value, must be "contract_creation")
|
|
let json = r#"
|
|
{
|
|
"to": {
|
|
"action": "some_invalid_value"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Unknown operator
|
|
let json = r#"
|
|
{
|
|
"to": {
|
|
"abc": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn valid_gas_operators() {
|
|
// Eq
|
|
let json = r#"
|
|
{
|
|
"gas": {
|
|
"eq": "0x493e0"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
gas: FilterOperator::Eq(U256::from(300_000)),
|
|
..default.clone()
|
|
});
|
|
|
|
// Gt
|
|
let json = r#"
|
|
{
|
|
"gas": {
|
|
"gt": "0x493e0"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
gas: FilterOperator::GreaterThan(U256::from(300_000)),
|
|
..default.clone()
|
|
});
|
|
|
|
// Lt
|
|
let json = r#"
|
|
{
|
|
"gas": {
|
|
"lt": "0x493e0"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
gas: FilterOperator::LessThan(U256::from(300_000)),
|
|
..default
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_gas_operators() {
|
|
// Multiple operators are invalid
|
|
let json = r#"
|
|
{
|
|
"gas": {
|
|
"eq": "0x493e0",
|
|
"lt": "0x493e0"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Action
|
|
let json = r#"
|
|
{
|
|
"gas": {
|
|
"action": "contract_creation"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Unknown operator
|
|
let json = r#"
|
|
{
|
|
"gas": {
|
|
"abc": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn valid_gas_price_operators() {
|
|
// Eq
|
|
let json = r#"
|
|
{
|
|
"gas_price": {
|
|
"eq": "0x12a05f200"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
gas_price: FilterOperator::Eq(U256::from(5_000_000_000 as i64)),
|
|
..default.clone()
|
|
});
|
|
|
|
// Gt
|
|
let json = r#"
|
|
{
|
|
"gas_price": {
|
|
"gt": "0x12a05f200"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
gas_price: FilterOperator::GreaterThan(U256::from(5_000_000_000 as i64)),
|
|
..default.clone()
|
|
});
|
|
|
|
// Lt
|
|
let json = r#"
|
|
{
|
|
"gas_price": {
|
|
"lt": "0x12a05f200"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
gas_price: FilterOperator::LessThan(U256::from(5_000_000_000 as i64)),
|
|
..default
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_gas_price_operators() {
|
|
// Multiple operators are invalid
|
|
let json = r#"
|
|
{
|
|
"gas_price": {
|
|
"eq": "0x12a05f200",
|
|
"lt": "0x12a05f200"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Action
|
|
let json = r#"
|
|
{
|
|
"gas_price": {
|
|
"action": "contract_creation"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Unknown operator
|
|
let json = r#"
|
|
{
|
|
"gas_price": {
|
|
"abc": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn valid_value_operators() {
|
|
// Eq
|
|
let json = r#"
|
|
{
|
|
"value": {
|
|
"eq": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
value: FilterOperator::Eq(U256::from(0)),
|
|
..default.clone()
|
|
});
|
|
|
|
// Gt
|
|
let json = r#"
|
|
{
|
|
"value": {
|
|
"gt": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
value: FilterOperator::GreaterThan(U256::from(0)),
|
|
..default.clone()
|
|
});
|
|
|
|
// Lt
|
|
let json = r#"
|
|
{
|
|
"value": {
|
|
"lt": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
value: FilterOperator::LessThan(U256::from(0)),
|
|
..default
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_value_operators() {
|
|
// Multiple operators are invalid
|
|
let json = r#"
|
|
{
|
|
"value": {
|
|
"eq": "0x0",
|
|
"lt": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Action
|
|
let json = r#"
|
|
{
|
|
"value": {
|
|
"action": "contract_creation"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Unknown operator
|
|
let json = r#"
|
|
{
|
|
"value": {
|
|
"abc": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn valid_nonce_operators() {
|
|
// Eq
|
|
let json = r#"
|
|
{
|
|
"nonce": {
|
|
"eq": "0x577"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
nonce: FilterOperator::Eq(U256::from(1399)),
|
|
..default.clone()
|
|
});
|
|
|
|
// Gt
|
|
let json = r#"
|
|
{
|
|
"nonce": {
|
|
"gt": "0x577"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
nonce: FilterOperator::GreaterThan(U256::from(1399)),
|
|
..default.clone()
|
|
});
|
|
|
|
// Lt
|
|
let json = r#"
|
|
{
|
|
"nonce": {
|
|
"lt": "0x577"
|
|
}
|
|
}
|
|
"#;
|
|
let default = FilterOptions::default();
|
|
let res = serde_json::from_str::<FilterOptions>(json).unwrap();
|
|
assert_eq!(res, FilterOptions {
|
|
nonce: FilterOperator::LessThan(U256::from(1399)),
|
|
..default
|
|
});
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_nonce_operators() {
|
|
// Multiple operators are invalid
|
|
let json = r#"
|
|
{
|
|
"nonce": {
|
|
"eq": "0x577",
|
|
"lt": "0x577"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Action
|
|
let json = r#"
|
|
{
|
|
"nonce": {
|
|
"action": "contract_creation"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
|
|
// Unknown operator
|
|
let json = r#"
|
|
{
|
|
"nonce": {
|
|
"abc": "0x0"
|
|
}
|
|
}
|
|
"#;
|
|
let res = serde_json::from_str::<FilterOptions>(json);
|
|
assert!(res.is_err());
|
|
}
|
|
}
|