fix(add helper for timestamp overflows) (#10330)
* fix(add helper timestamp overflows) * fix(simplify code) * fix(make helper private)
This commit is contained in:
parent
d89b8d904f
commit
d8394bded7
@ -89,6 +89,8 @@ pub enum BlockError {
|
||||
InvalidNumber(Mismatch<BlockNumber>),
|
||||
/// Block number isn't sensible.
|
||||
RidiculousNumber(OutOfBounds<BlockNumber>),
|
||||
/// Timestamp header overflowed
|
||||
TimestampOverflow,
|
||||
/// Too many transactions from a particular address.
|
||||
TooManyTransactions(Address),
|
||||
/// Parent given is unknown.
|
||||
@ -138,6 +140,7 @@ impl fmt::Display for BlockError {
|
||||
UnknownParent(ref hash) => format!("Unknown parent: {}", hash),
|
||||
UnknownUncleParent(ref hash) => format!("Unknown uncle parent: {}", hash),
|
||||
UnknownEpochTransition(ref num) => format!("Unknown transition to epoch number: {}", num),
|
||||
TimestampOverflow => format!("Timestamp overflow"),
|
||||
TooManyTransactions(ref address) => format!("Too many transactions from: {}", address),
|
||||
};
|
||||
|
||||
|
@ -40,6 +40,25 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// Preprocessed block data gathered in `verify_block_unordered` call
|
||||
pub struct PreverifiedBlock {
|
||||
/// Populated block header
|
||||
@ -306,7 +325,7 @@ pub fn verify_header_params(header: &Header, engine: &EthEngine, is_full: bool,
|
||||
const ACCEPTABLE_DRIFT: Duration = Duration::from_secs(15);
|
||||
let max_time = SystemTime::now() + ACCEPTABLE_DRIFT;
|
||||
let invalid_threshold = max_time + ACCEPTABLE_DRIFT * 9;
|
||||
let timestamp = UNIX_EPOCH + Duration::from_secs(header.timestamp());
|
||||
let timestamp = timestamp_checked_add(UNIX_EPOCH, Duration::from_secs(header.timestamp()))?;
|
||||
|
||||
if timestamp > invalid_threshold {
|
||||
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: Some(max_time), min: None, found: timestamp })))
|
||||
@ -328,8 +347,8 @@ 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 = SystemTime::now() + Duration::from_secs(parent.timestamp() + 1);
|
||||
let found = SystemTime::now() + Duration::from_secs(header.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()))?;
|
||||
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(min), found })))
|
||||
}
|
||||
if header.number() != parent.number() + 1 {
|
||||
@ -743,7 +762,8 @@ mod tests {
|
||||
check_fail_timestamp(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), false);
|
||||
|
||||
header = good.clone();
|
||||
header.set_timestamp(2450000000);
|
||||
// will return `BlockError::TimestampOverflow` when timestamp > `i32::max_value()`
|
||||
header.set_timestamp(i32::max_value() as u64);
|
||||
check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine), false);
|
||||
|
||||
header = good.clone();
|
||||
@ -815,4 +835,11 @@ 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());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user