fix: disambiguate use of next when validating ForkId (#8320)

This commit is contained in:
Federico Gimenez
2024-05-21 16:24:15 +02:00
committed by GitHub
parent c97963b354
commit 106d449307

View File

@ -21,6 +21,7 @@ use std::{
use thiserror::Error;
const CRC_32_IEEE: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
const TIMESTAMP_BEFORE_ETHEREUM_MAINNET: u64 = 1_300_000_000;
/// `CRC32` hash of all previous forks starting from genesis block.
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
@ -313,16 +314,25 @@ impl ForkFilter {
return Ok(())
}
// We check if this fork is time-based or block number-based
// NOTE: This is a bit hacky but I'm unsure how else we can figure out when to use
// timestamp vs when to use block number..
let head_block_or_time = match self.cache.epoch_start {
ForkFilterKey::Block(_) => self.head.number,
ForkFilterKey::Time(_) => self.head.timestamp,
let is_incompatible = if self.head.number < TIMESTAMP_BEFORE_ETHEREUM_MAINNET {
// When the block number is less than an old timestamp before Ethereum mainnet,
// we check if this fork is time-based or block number-based by estimating that,
// if fork_id.next is bigger than the old timestamp, we are dealing with a
// timestamp, otherwise with a block.
(fork_id.next > TIMESTAMP_BEFORE_ETHEREUM_MAINNET &&
self.head.timestamp >= fork_id.next) ||
(fork_id.next <= TIMESTAMP_BEFORE_ETHEREUM_MAINNET &&
self.head.number >= fork_id.next)
} else {
// Extra safety check to future-proof for when Ethereum has over a billion blocks.
let head_block_or_time = match self.cache.epoch_start {
ForkFilterKey::Block(_) => self.head.number,
ForkFilterKey::Time(_) => self.head.timestamp,
};
head_block_or_time >= fork_id.next
};
//... compare local head to FORK_NEXT.
return if head_block_or_time >= fork_id.next {
return if is_incompatible {
// 1a) A remotely announced but remotely not passed block is already passed locally,
// disconnect, since the chains are incompatible.
Err(ValidationError::LocalIncompatibleOrStale {
@ -588,6 +598,72 @@ mod tests {
filter.validate(remote),
Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote })
);
// Block far in the future (block number bigger than TIMESTAMP_BEFORE_ETHEREUM_MAINNET), not
// compatible.
filter
.set_head(Head { number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 1, ..Default::default() });
let remote = ForkId {
hash: ForkHash(hex!("668db0af")),
next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 1,
};
assert_eq!(
filter.validate(remote),
Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote })
);
// Block far in the future (block number bigger than TIMESTAMP_BEFORE_ETHEREUM_MAINNET),
// compatible.
filter
.set_head(Head { number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 1, ..Default::default() });
let remote = ForkId {
hash: ForkHash(hex!("668db0af")),
next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 2,
};
assert_eq!(filter.validate(remote), Ok(()));
// block number smaller than TIMESTAMP_BEFORE_ETHEREUM_MAINNET and
// fork_id.next > TIMESTAMP_BEFORE_ETHEREUM_MAINNET && self.head.timestamp >= fork_id.next,
// not compatible.
filter.set_head(Head {
number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 1,
timestamp: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 2,
..Default::default()
});
let remote = ForkId {
hash: ForkHash(hex!("668db0af")),
next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 1,
};
assert_eq!(
filter.validate(remote),
Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote })
);
// block number smaller than TIMESTAMP_BEFORE_ETHEREUM_MAINNET and
// fork_id.next <= TIMESTAMP_BEFORE_ETHEREUM_MAINNET && self.head.number >= fork_id.next,
// not compatible.
filter
.set_head(Head { number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 1, ..Default::default() });
let remote = ForkId {
hash: ForkHash(hex!("668db0af")),
next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 2,
};
assert_eq!(
filter.validate(remote),
Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote })
);
// block number smaller than TIMESTAMP_BEFORE_ETHEREUM_MAINNET and
// !((fork_id.next > TIMESTAMP_BEFORE_ETHEREUM_MAINNET && self.head.timestamp >=
// fork_id.next) || (fork_id.next <= TIMESTAMP_BEFORE_ETHEREUM_MAINNET && self.head.number
// >= fork_id.next)), compatible.
filter
.set_head(Head { number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 2, ..Default::default() });
let remote = ForkId {
hash: ForkHash(hex!("668db0af")),
next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 1,
};
assert_eq!(filter.validate(remote), Ok(()));
}
#[test]