Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(anvil): support mining with same block.timestamp #9160

Merged
merged 3 commits into from
Oct 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions crates/anvil/src/eth/backend/time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ impl TimeManager {
/// Fails if it's before (or at the same time) the last timestamp
pub fn set_next_block_timestamp(&self, timestamp: u64) -> Result<(), BlockchainError> {
trace!(target: "time", "override next timestamp {}", timestamp);
if timestamp <= *self.last_timestamp.read() {
if timestamp < *self.last_timestamp.read() {
return Err(BlockchainError::TimestampError(format!(
"{timestamp} is lower than or equal to previous block's timestamp"
"{timestamp} is lower than previous block's timestamp"
)))
}
self.next_exact_timestamp.write().replace(timestamp);
Expand Down Expand Up @@ -112,7 +112,7 @@ impl TimeManager {
(current.saturating_add(self.offset()) as u64, false)
};
// Ensures that the timestamp is always increasing
if next_timestamp <= last_timestamp {
if next_timestamp < last_timestamp {
next_timestamp = last_timestamp + 1;
}
let next_offset = update_offset.then_some((next_timestamp as i128) - current);
Expand Down
127 changes: 124 additions & 3 deletions crates/anvil/tests/it/anvil_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,7 +315,7 @@ async fn test_set_next_timestamp() {
let next = provider.get_block(BlockId::default(), false.into()).await.unwrap().unwrap();
assert_eq!(next.header.number, 2);

assert!(next.header.timestamp > block.header.timestamp);
assert!(next.header.timestamp >= block.header.timestamp);
}

#[tokio::test(flavor = "multi_thread")]
Expand All @@ -339,7 +339,7 @@ async fn test_evm_set_time() {
api.evm_mine(None).await.unwrap();
let next = provider.get_block(BlockId::default(), false.into()).await.unwrap().unwrap();

assert!(next.header.timestamp > block.header.timestamp);
assert!(next.header.timestamp >= block.header.timestamp);
}

#[tokio::test(flavor = "multi_thread")]
Expand Down Expand Up @@ -608,7 +608,7 @@ async fn test_fork_revert_next_block_timestamp() {

api.mine_one().await;
let block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();
assert!(block.header.timestamp > latest_block.header.timestamp);
assert!(block.header.timestamp >= latest_block.header.timestamp);
}

// test that after a snapshot revert, the env block is reset
Expand Down Expand Up @@ -888,3 +888,124 @@ async fn test_arb_get_block() {

assert_eq!(block.header.number, 1);
}

// Set next_block_timestamp same as previous block
// api.evm_set_next_block_timestamp(0).unwrap();
#[tokio::test(flavor = "multi_thread")]
async fn test_mine_blk_with_prev_timestamp() {
let (api, handle) = spawn(NodeConfig::test()).await;
let provider = handle.http_provider();

let init_blk = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap();

let init_number = init_blk.header.number;
let init_timestamp = init_blk.header.timestamp;

// mock timestamp
api.evm_set_next_block_timestamp(init_timestamp).unwrap();

api.mine_one().await;

let block = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap();

let next_blk_num = block.header.number;
let next_blk_timestamp = block.header.timestamp;

assert_eq!(next_blk_num, init_number + 1);
assert_eq!(next_blk_timestamp, init_timestamp);

// Sleep for 1 second
tokio::time::sleep(Duration::from_secs(1)).await;

// Subsequent block should have a greater timestamp than previous block
api.mine_one().await;

let block = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap();

let third_blk_num = block.header.number;
let third_blk_timestmap = block.header.timestamp;

assert_eq!(third_blk_num, init_number + 2);
assert_ne!(third_blk_timestmap, next_blk_timestamp);
assert!(third_blk_timestmap > next_blk_timestamp);
}

// increase time by 0 seconds i.e next_block_timestamp = prev_block_timestamp
// api.evm_increase_time(0).unwrap();
#[tokio::test(flavor = "multi_thread")]
async fn test_increase_time_by_zero() {
let (api, handle) = spawn(NodeConfig::test()).await;
let provider = handle.http_provider();

let init_blk = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap();

let init_number = init_blk.header.number;
let init_timestamp = init_blk.header.timestamp;

let _ = api.evm_increase_time(U256::ZERO).await;

api.mine_one().await;

let block = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap();

let next_blk_num = block.header.number;
let next_blk_timestamp = block.header.timestamp;

assert_eq!(next_blk_num, init_number + 1);
assert_eq!(next_blk_timestamp, init_timestamp);
}

// evm_mine(MineOptions::Timestamp(prev_block_timestamp))
#[tokio::test(flavor = "multi_thread")]
async fn evm_mine_blk_with_same_timestamp() {
let (api, handle) = spawn(NodeConfig::test()).await;
let provider = handle.http_provider();

let init_blk = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap();

let init_number = init_blk.header.number;
let init_timestamp = init_blk.header.timestamp;

api.evm_mine(Some(MineOptions::Timestamp(Some(init_timestamp)))).await.unwrap();

let block = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap();

let next_blk_num = block.header.number;
let next_blk_timestamp = block.header.timestamp;

assert_eq!(next_blk_num, init_number + 1);
assert_eq!(next_blk_timestamp, init_timestamp);
}

// mine 4 blocks instantly.
#[tokio::test(flavor = "multi_thread")]
async fn test_mine_blks_with_same_timestamp() {
let (api, handle) = spawn(NodeConfig::test()).await;
let provider = handle.http_provider();

let init_blk = provider.get_block(BlockId::latest(), false.into()).await.unwrap().unwrap();

let init_number = init_blk.header.number;
let init_timestamp = init_blk.header.timestamp;

// Mine 4 blocks instantly
let _ = api.anvil_mine(Some(U256::from(4)), None).await;

let latest_blk_num = api.block_number().unwrap().to::<u64>();

assert_eq!(latest_blk_num, init_number + 4);

let mut blk_futs = vec![];
for i in 1..=4 {
blk_futs.push(provider.get_block(i.into(), false.into()));
}

let blks = futures::future::join_all(blk_futs)
.await
.into_iter()
.map(|blk| blk.unwrap().unwrap().header.timestamp)
.collect::<Vec<_>>();

// timestamps should be equal
assert_eq!(blks, vec![init_timestamp; 4]);
}
2 changes: 1 addition & 1 deletion crates/anvil/tests/it/fork.rs
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,7 @@ async fn test_fork_block_timestamp() {
api.anvil_mine(Some(U256::from(1)), None).await.unwrap();
let latest_block = api.block_by_number(BlockNumberOrTag::Latest).await.unwrap().unwrap();

assert!(initial_block.header.timestamp < latest_block.header.timestamp);
assert!(initial_block.header.timestamp <= latest_block.header.timestamp);
}

#[tokio::test(flavor = "multi_thread")]
Expand Down
Loading