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

Commit

Permalink
fix(extract timestamp_checked_add as lib)
Browse files Browse the repository at this point in the history
  • Loading branch information
niklasad1 committed Feb 19, 2019
1 parent ca67dc2 commit 80841b2
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 42 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ members = [
"util/triehash-ethereum",
"util/keccak-hasher",
"util/patricia-trie-ethereum",
"util/fastmap"
"util/fastmap",
"util/time-utils"
]

[patch.crates-io]
Expand Down
1 change: 1 addition & 0 deletions ethcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ serde = "1.0"
serde_derive = "1.0"
stats = { path = "../util/stats" }
tempdir = {version="0.3", optional = true}
time-utils = { path = "../util/time-utils" }
trace-time = "0.1"
triehash-ethereum = { version = "0.2", path = "../util/triehash-ethereum" }
unexpected = { path = "../util/unexpected" }
Expand Down
16 changes: 13 additions & 3 deletions ethcore/src/engines/authority_round/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ use itertools::{self, Itertools};
use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, Rlp};
use ethereum_types::{H256, H520, Address, U128, U256};
use parking_lot::{Mutex, RwLock};
use time_utils::CheckedSystemTime;
use types::BlockNumber;
use types::header::{Header, ExtendedHeader};
use types::ancestry_action::AncestryAction;
Expand Down Expand Up @@ -570,8 +571,16 @@ fn verify_timestamp(step: &Step, header_step: u64) -> Result<(), BlockError> {
// NOTE This error might be returned only in early stage of verification (Stage 1).
// Returning it further won't recover the sync process.
trace!(target: "engine", "verify_timestamp: block too early");
let oob = oob.map(|n| SystemTime::now() + Duration::from_secs(n));
Err(BlockError::TemporarilyInvalid(oob).into())

let now = SystemTime::now();
let found = CheckedSystemTime::checked_add(now, Duration::from_secs(oob.found))
.ok_or(BlockError::TimestampOverflow)?;
let max = oob.max.and_then(|m| CheckedSystemTime::checked_add(now, Duration::from_secs(m)));
let min = oob.max.and_then(|m| CheckedSystemTime::checked_add(now, Duration::from_secs(m)));

let new_oob = OutOfBounds { min, max, found };

Err(BlockError::TemporarilyInvalid(new_oob).into())
},
Ok(_) => Ok(()),
}
Expand Down Expand Up @@ -607,6 +616,7 @@ fn combine_proofs(signal_number: BlockNumber, set_proof: &[u8], finality_proof:
stream.out()
}


fn destructure_proofs(combined: &[u8]) -> Result<(BlockNumber, &[u8], &[u8]), Error> {
let rlp = Rlp::new(combined);
Ok((
Expand All @@ -622,7 +632,7 @@ trait AsMillis {

impl AsMillis for Duration {
fn as_millis(&self) -> u64 {
self.as_secs()*1_000 + (self.subsec_nanos()/1_000_000) as u64
self.as_secs() * 1_000 + (self.subsec_nanos() / 1_000_000) as u64
}
}

Expand Down
1 change: 1 addition & 0 deletions ethcore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ extern crate rlp;
extern crate rustc_hex;
extern crate serde;
extern crate stats;
extern crate time_utils;
extern crate triehash_ethereum as triehash;
extern crate unexpected;
extern crate using_queue;
Expand Down
37 changes: 8 additions & 29 deletions ethcore/src/verification/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,25 +39,7 @@ use error::{BlockError, Error};
use types::{BlockNumber, header::Header};
use types::transaction::SignedTransaction;
use verification::queue::kind::blocks::Unverified;


/// Returns `Ok<SystemTime>` when the result less or equal to `i32::max_value` to prevent `SystemTime` to panic because
/// it is platform specific, may be i32 or i64.
///
/// `Err<BlockError::TimestampOver` otherwise.
///
// FIXME: @niklasad1 - remove this when and use `SystemTime::checked_add`
// when https://github.com/rust-lang/rust/issues/55940 is stabilized.
fn timestamp_checked_add(sys: SystemTime, d2: Duration) -> Result<SystemTime, BlockError> {
let d1 = sys.duration_since(UNIX_EPOCH).map_err(|_| BlockError::TimestampOverflow)?;
let total_time = d1.checked_add(d2).ok_or(BlockError::TimestampOverflow)?;

if total_time.as_secs() <= i32::max_value() as u64 {
Ok(sys + d2)
} else {
Err(BlockError::TimestampOverflow)
}
}
use time_utils::CheckedSystemTime;

/// Preprocessed block data gathered in `verify_block_unordered` call
pub struct PreverifiedBlock {
Expand Down Expand Up @@ -323,9 +305,11 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool,

if is_full {
const ACCEPTABLE_DRIFT: Duration = Duration::from_secs(15);
// this will resist overflow until `2037`
let max_time = SystemTime::now() + ACCEPTABLE_DRIFT;
let invalid_threshold = max_time + ACCEPTABLE_DRIFT * 9;
let timestamp = timestamp_checked_add(UNIX_EPOCH, Duration::from_secs(header.timestamp()))?;
let timestamp = CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(header.timestamp()))
.ok_or(BlockError::TimestampOverflow)?;

if timestamp > invalid_threshold {
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: timestamp })))
Expand All @@ -347,8 +331,10 @@ fn verify_parent(header: &Header, parent: &Header, engine: &EthEngine) -> Result
let gas_limit_divisor = engine.params().gas_limit_bound_divisor;

if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) {
let min = timestamp_checked_add(SystemTime::now(), Duration::from_secs(parent.timestamp().saturating_add(1)))?;
let found = timestamp_checked_add(SystemTime::now(), Duration::from_secs(header.timestamp()))?;
let min = CheckedSystemTime::checked_add(SystemTime::now(), Duration::from_secs(parent.timestamp().saturating_add(1)))
.ok_or(BlockError::TimestampOverflow)?;
let found = CheckedSystemTime::checked_add(SystemTime::now(), Duration::from_secs(header.timestamp()))
.ok_or(BlockError::TimestampOverflow)?;
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(min), found })))
}
if header.number() != parent.number() + 1 {
Expand Down Expand Up @@ -835,11 +821,4 @@ mod tests {
check_fail(unordered_test(&create_test_block_with_data(&header, &bad_transactions, &[]), &engine), TooManyTransactions(keypair.address()));
unordered_test(&create_test_block_with_data(&header, &good_transactions, &[]), &engine).unwrap();
}

#[test]
fn checked_add_systime_dur() {
assert!(timestamp_checked_add(UNIX_EPOCH, Duration::new(i32::max_value() as u64 + 1, 0)).is_err());
assert!(timestamp_checked_add(UNIX_EPOCH, Duration::new(i32::max_value() as u64, 0)).is_ok());
assert!(timestamp_checked_add(UNIX_EPOCH, Duration::new(i32::max_value() as u64 - 1, 1_000_000_000)).is_ok());
}
}
9 changes: 9 additions & 0 deletions util/time-utils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "time-utils"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
description = "Time utilities for checked arithmetic"
license = "GPL3"
edition = "2018"

[dependencies]
62 changes: 62 additions & 0 deletions util/time-utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use std::time::{Duration, SystemTime, UNIX_EPOCH};

/// Temporary trait for `SystemTime::checked_add` until `Rust 1.33` is available
pub trait CheckedSystemTime {
/// Returns `Some<SystemTime>` when the result less or equal to `i32::max_value` to prevent `SystemTime` to panic because
/// it is platform specific, possible representations are i32, i64, u64 and Duration. `None` otherwise
fn checked_add(self, _d: Duration) -> Option<SystemTime>;
/// Returns `Some<SystemTime>` when the result is successful and `None` when it is not
fn checked_sub(self, _d: Duration) -> Option<SystemTime>;
}

impl CheckedSystemTime for SystemTime {
fn checked_add(self, dur: Duration) -> Option<SystemTime> {
let this_dur = self.duration_since(UNIX_EPOCH).ok()?;
let total_time = this_dur.checked_add(dur)?;

if total_time.as_secs() <= i32::max_value() as u64 {
Some(self + dur)
} else {
None
}
}

fn checked_sub(self, dur: Duration) -> Option<SystemTime> {
let this_dur = self.duration_since(UNIX_EPOCH).ok()?;
let total_time = this_dur.checked_sub(dur)?;

if total_time.as_secs() <= i32::max_value() as u64 {
Some(self - dur)
} else {
None
}
}
}

/// Temporary trait for `Duration::as_millis` until `Rust 1.33` is available
pub trait AsMillis {
/// Duration represented as milliseconds
fn as_millis(&self) -> u128;
}

impl AsMillis for Duration {
fn as_millis(&self) -> u128 {
self.as_secs() as u128 * 1_000 + (self.subsec_nanos() / 1_000_000) as u128
}
}

#[cfg(test)]
mod tests {
#[test]
fn it_works() {
use super::CheckedSystemTime;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

assert!(CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::new(i32::max_value() as u64 + 1, 0)).is_none());
assert!(CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::new(i32::max_value() as u64, 0)).is_some());
assert!(CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::new(i32::max_value() as u64 - 1, 1_000_000_000)).is_some());

assert!(CheckedSystemTime::checked_sub(UNIX_EPOCH, Duration::from_secs(120)).is_none());
assert!(CheckedSystemTime::checked_sub(SystemTime::now(), Duration::from_secs(1000)).is_some());
}
}
1 change: 1 addition & 0 deletions whisper/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ serde_json = "1.0"
slab = "0.3"
smallvec = "0.6"
tiny-keccak = "1.4"
time-utils = { path = "../util/time-utils" }

jsonrpc-core = "10.0.1"
jsonrpc-derive = "10.0.2"
Expand Down
1 change: 1 addition & 0 deletions whisper/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ extern crate serde;
extern crate slab;
extern crate smallvec;
extern crate tiny_keccak;
extern crate time_utils;

extern crate jsonrpc_core;
extern crate jsonrpc_derive;
Expand Down
19 changes: 13 additions & 6 deletions whisper/src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use ethereum_types::{H256, H512};
use rlp::{self, DecoderError, RlpStream, Rlp};
use smallvec::SmallVec;
use tiny_keccak::{keccak256, Keccak};
use time_utils::CheckedSystemTime;

/// Work-factor proved. Takes 3 parameters: size of message, time to live,
/// and hash.
Expand Down Expand Up @@ -117,6 +118,7 @@ pub enum Error {
EmptyTopics,
LivesTooLong,
IssuedInFuture,
TimestampOverflow,
ZeroTTL,
}

Expand All @@ -133,6 +135,7 @@ impl fmt::Display for Error {
Error::LivesTooLong => write!(f, "Message claims to be issued before the unix epoch."),
Error::IssuedInFuture => write!(f, "Message issued in future."),
Error::ZeroTTL => write!(f, "Message live for zero time."),
Error::TimestampOverflow => write!(f, "Timestamp overflow"),
Error::EmptyTopics => write!(f, "Message has no topics."),
}
}
Expand Down Expand Up @@ -255,11 +258,11 @@ pub struct Message {
impl Message {
/// Create a message from creation parameters.
/// Panics if TTL is 0.
pub fn create(params: CreateParams) -> Result<Self, EmptyTopics> {
pub fn create(params: CreateParams) -> Result<Self, Error> {
use byteorder::{BigEndian, ByteOrder};
use rand::{Rng, SeedableRng, XorShiftRng};

if params.topics.is_empty() { return Err(EmptyTopics) }
if params.topics.is_empty() { return Err(Error::EmptyTopics) }

let mut rng = {
let mut thread_rng = ::rand::thread_rng();
Expand All @@ -270,7 +273,8 @@ impl Message {
assert!(params.ttl > 0);

let expiry = {
let after_mining = SystemTime::now() + Duration::from_millis(params.work);
let after_mining = CheckedSystemTime::checked_add(SystemTime::now(), Duration::from_millis(params.work)).
ok_or(Error::TimestampOverflow)?;
let since_epoch = after_mining.duration_since(time::UNIX_EPOCH)
.expect("time after now is after unix epoch; qed");

Expand Down Expand Up @@ -357,7 +361,10 @@ impl Message {
(envelope.expiry - envelope.ttl).saturating_sub(LEEWAY_SECONDS)
);

if time::UNIX_EPOCH + issue_time_adjusted > now {
let issue_time_adjusted = CheckedSystemTime::checked_add(time::UNIX_EPOCH, issue_time_adjusted)
.ok_or(Error::TimestampOverflow)?;

if issue_time_adjusted > now {
return Err(Error::IssuedInFuture);
}

Expand Down Expand Up @@ -400,8 +407,8 @@ impl Message {
}

/// Get the expiry time.
pub fn expiry(&self) -> SystemTime {
time::UNIX_EPOCH + Duration::from_secs(self.envelope.expiry)
pub fn expiry(&self) -> Option<SystemTime> {
CheckedSystemTime::checked_add(time::UNIX_EPOCH, Duration::from_secs(self.envelope.expiry))
}

/// Get the topics.
Expand Down
9 changes: 6 additions & 3 deletions whisper/src/net/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,10 @@ impl Messages {
}
}

let expiry = message.expiry();
let expiry = match message.expiry() {
Some(time) => time,
_ => return false,
};

self.cumulative_size += message.encoded_size();

Expand All @@ -232,8 +235,8 @@ impl Messages {

let sorted_entry = SortedEntry {
slab_id: id,
work_proved: work_proved,
expiry: expiry,
work_proved,
expiry,
};

match self.sorted.binary_search(&sorted_entry) {
Expand Down

0 comments on commit 80841b2

Please sign in to comment.