Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
spec: Validate required divisor fields are not 0 (#7933)
Browse files Browse the repository at this point in the history
* Add validate_non_zero function

It's used to validate that a Spec's uint field used as a divisor is not zero.

* Add deserialize_with to gas_limit_bound_divisor

Prevents panics due to divide-by-zero on the gas_limit_bound_divisor
field.

* Add deserialize_with to difficulty_bound_divisor

Prevents panics due to divide-by-zero on the difficulty_bound_divisor
field.

* Add validate_optional_non_zero function

Used to validate Option<Uint> divisor fields.

* Use deserialize_with on optional divisor fields.

* Add #[serde(default)] attribute to divisor fields

When using `#[serde(deserialize_with)]`, `#[serde(default)]` must be specified so that missing
fields can be deserialized with the deserializer for `None`.
  • Loading branch information
asymmetric authored and 5chdn committed Feb 19, 2018
1 parent 76a0981 commit e630f64
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 3 deletions.
19 changes: 18 additions & 1 deletion json/src/spec/ethash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

//! Ethash params deserialization.

use uint::Uint;
use uint::{self, Uint};
use hash::Address;

/// Deserializable doppelganger of EthashParams.
Expand All @@ -27,12 +27,15 @@ pub struct EthashParams {
pub minimum_difficulty: Uint,
/// See main EthashParams docs.
#[serde(rename="difficultyBoundDivisor")]
#[serde(deserialize_with="uint::validate_non_zero")]
pub difficulty_bound_divisor: Uint,
/// See main EthashParams docs.
#[serde(rename="difficultyIncrementDivisor")]
#[serde(default, deserialize_with="uint::validate_optional_non_zero")]
pub difficulty_increment_divisor: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="metropolisDifficultyIncrementDivisor")]
#[serde(default, deserialize_with="uint::validate_optional_non_zero")]
pub metropolis_difficulty_increment_divisor: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="durationLimit")]
Expand Down Expand Up @@ -60,6 +63,7 @@ pub struct EthashParams {
pub difficulty_hardfork_transition: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="difficultyHardforkBoundDivisor")]
#[serde(default, deserialize_with="uint::validate_optional_non_zero")]
pub difficulty_hardfork_bound_divisor: Option<Uint>,
/// See main EthashParams docs.
#[serde(rename="bombDefuseTransition")]
Expand Down Expand Up @@ -302,4 +306,17 @@ mod tests {
}
});
}

#[test]
#[should_panic(expected = "a non-zero value")]
fn test_zero_value_divisor() {
let s = r#"{
"params": {
"difficultyBoundDivisor": "0x0",
"minimumDifficulty": "0x020000"
}
}"#;

let _deserialized: Ethash = serde_json::from_str(s).unwrap();
}
}
20 changes: 19 additions & 1 deletion json/src/spec/params.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

//! Spec params deserialization.

use uint::Uint;
use uint::{self, Uint};
use hash::{H256, Address};
use bytes::Bytes;

Expand Down Expand Up @@ -102,6 +102,7 @@ pub struct Params {
pub wasm: Option<bool>,
/// See `CommonParams` docs.
#[serde(rename="gasLimitBoundDivisor")]
#[serde(deserialize_with="uint::validate_non_zero")]
pub gas_limit_bound_divisor: Uint,
/// See `CommonParams` docs.
pub registrar: Option<Address>,
Expand Down Expand Up @@ -149,4 +150,21 @@ mod tests {
assert_eq!(deserialized.gas_limit_bound_divisor, Uint(U256::from(0x20)));
assert_eq!(deserialized.max_code_size, Some(Uint(U256::from(0x1000))));
}

#[test]
#[should_panic(expected = "a non-zero value")]
fn test_zero_value_divisor() {
let s = r#"{
"maximumExtraDataSize": "0x20",
"networkID" : "0x1",
"chainID" : "0x15",
"subprotocolName" : "exp",
"minGasLimit": "0x1388",
"accountStartNonce": "0x01",
"gasLimitBoundDivisor": "0x0",
"maxCodeSize": "0x1000"
}"#;

let _deserialized: Params = serde_json::from_str(s).unwrap();
}
}
24 changes: 23 additions & 1 deletion json/src/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use std::fmt;
use std::str::FromStr;
use serde::{Deserialize, Deserializer};
use serde::de::{Error, Visitor};
use serde::de::{Error, Visitor, Unexpected};
use ethereum_types::U256;

/// Lenient uint json deserialization for test json files.
Expand Down Expand Up @@ -90,6 +90,28 @@ impl<'a> Visitor<'a> for UintVisitor {
}
}

pub fn validate_non_zero<'de, D>(d: D) -> Result<Uint, D::Error> where D: Deserializer<'de> {
let value = Uint::deserialize(d)?;

if value == Uint(U256::from(0)) {
return Err(Error::invalid_value(Unexpected::Unsigned(value.into()), &"a non-zero value"))
}

Ok(value)
}

pub fn validate_optional_non_zero<'de, D>(d: D) -> Result<Option<Uint>, D::Error> where D: Deserializer<'de> {
let value: Option<Uint> = Option::deserialize(d)?;

if let Some(value) = value {
if value == Uint(U256::from(0)) {
return Err(Error::invalid_value(Unexpected::Unsigned(value.into()), &"a non-zero value"))
}
}

Ok(value)
}

#[cfg(test)]
mod test {
use serde_json;
Expand Down

0 comments on commit e630f64

Please sign in to comment.