Skip to content
Open
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
67 changes: 67 additions & 0 deletions src/payload/checkpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,70 @@ impl<P: Platform> Display for Checkpoint<P> {
}
}
}

#[cfg(test)]
mod tests {
use {
rblib::{prelude::*, test_utils::BlockContextMocked},
std::time::Instant,
};

#[test]
fn test_barrier_depth_and_is_barrier() {
let (block, _) = BlockContext::<Ethereum>::mocked();

let checkpoint = block.start();

// Expected: initial checkpoint is depth 0 and is barrier
assert_eq!(checkpoint.depth(), 0);
assert!(checkpoint.is_barrier());
assert!(checkpoint.prev().is_none());
}
Comment on lines +528 to +538
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use new_at_block instead of BlockContext::start


#[test]
fn test_named_barrier_and_prev_depth() {
// Outline:
// 1. create initial checkpoint (depth 0)
// 2. create named barrier on top
// 3. verify new depth is 1, prev is initial, and is_named_barrier returns
// true
let root = {
let (block, _) = BlockContext::<Ethereum>::mocked();

let cp = block.start();
cp
};

let named = root.named_barrier("sequencer-synced");
assert_eq!(named.depth(), root.depth() + 1);
assert!(named.is_named_barrier("sequencer-synced"));
assert!(matches!(named.prev(), Some(_)));
assert_eq!(named.prev().unwrap().depth(), root.depth());
}
Comment on lines +540 to +559
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this for now. We're reworking named barrier in #35


#[test]
fn test_created_at() {
let (block, _) = BlockContext::<Ethereum>::mocked();

let checkpoint = block.start();

let now = Instant::now();
assert!(checkpoint.created_at() <= now);
Comment on lines +564 to +568
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to be more precise, i.e. like:

let before = Instant::now();
let cp = block.start();
let after = Instant::now();
assert!((before..=after).contains(&cp.created_at()));

}

#[test]
fn test_iter() {
let (block, _) = BlockContext::<Ethereum>::mocked();

let checkpoint = block.start();

let checkpoint2 = checkpoint.barrier();
let checkpoint3 = checkpoint2.barrier();

let history: Vec<_> = checkpoint3.into_iter().collect();
assert_eq!(history.len(), 3);
assert_eq!(history[0].depth(), 2);
assert_eq!(history[1].depth(), 1);
assert_eq!(history[2].depth(), 0);
Comment on lines +577 to +584
Copy link
Collaborator

@julio4 julio4 Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you also add a checkpoint with an executable (tx/bundle).
And not only test depth but also that the yielded items are the ones expected.

}
}
105 changes: 105 additions & 0 deletions src/payload/ext/checkpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,108 @@ impl<P: Platform> CheckpointExt<P> for Checkpoint<P> {
self.root().created_at()
}
}

#[cfg(test)]
mod tests {
use {
crate::alloy::primitives::Address,
alloy_origin::primitives::{TxHash, U256},
rblib::{prelude::*, test_utils::BlockContextMocked},
std::{
thread,
time::{Duration, Instant},
},
};

#[test]
fn test_is_empty_and_root() {
let (block, _) = BlockContext::<Ethereum>::mocked();
let root = block.start();
let mid = root.barrier();
let leaf = mid.barrier();

assert!(root.is_empty());
assert_eq!(leaf.root(), root);
}

#[test]
fn test_gas_used_and_cumulative_gas_used() {
let (block, _) = BlockContext::<Ethereum>::mocked();
let cp = block.start();
assert_eq!(cp.gas_used(), 0);
assert_eq!(cp.cumulative_gas_used(), 0);
}

#[test]
fn test_effective_tip_and_blob_gas() {
let (block, _) = BlockContext::<Ethereum>::mocked();
let cp = block.start();
assert_eq!(cp.effective_tip_per_gas(), 0);
assert!(!cp.has_blobs());
assert_eq!(cp.blob_gas_used(), Some(0));
assert_eq!(cp.cumulative_blob_gas_used(), 0);
}

#[test]
fn test_to_between_linear_history() {
let (block, _) = BlockContext::<Ethereum>::mocked();
let a = block.start();
let b = a.barrier();
let c = b.barrier();

let span1 = c.to(&a).unwrap();
let span2 = a.to(&c).unwrap();

assert_eq!(span1.len(), 3);
assert_eq!(span2.len(), 3);
Comment on lines +363 to +367
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

span1 and span2 are equivalent.
Could you iterate over history and make sure it is the correct span.

to is quite complex so there are multiple tests to do:

  • non linear error
  • correct history when traversing back and forth
  • to(x, y) equivalence with to(y, x)
    and try to find edge cases in general

}

#[test]
fn test_balance_and_nonce_defaults() {
let (block, _) = BlockContext::<Ethereum>::mocked();
let cp = block.start();

let addr = Address::ZERO;
assert_eq!(cp.balance_of(addr).unwrap(), U256::ZERO);
assert_eq!(cp.nonce_of(addr).unwrap(), 0);
}

#[test]
fn test_signers_and_nonces_are_empty() {
let (block, _) = BlockContext::<Ethereum>::mocked();
let cp = block.start();

assert!(cp.signers().is_empty());
assert!(cp.nonces().is_empty());
}

#[test]
fn test_hash_and_is_bundle_and_has_failures_defaults() {
let (block, _) = BlockContext::<Ethereum>::mocked();
let cp = block.start();

assert_eq!(cp.hash(), None);
assert!(!cp.is_bundle());
Comment on lines +327 to +395
Copy link
Collaborator

@julio4 julio4 Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For all the default values for the initial checkpoint, can you move all the checks in a single test test_new_at_block.

assert!(!cp.has_failures());
assert_eq!(cp.failed_txs().count(), 0);
}

#[test]
fn test_contains_is_false_without_txs() {
let (block, _) = BlockContext::<Ethereum>::mocked();
let cp = block.start();

let fake_hash = TxHash::repeat_byte(0x42);
assert!(!cp.contains(fake_hash));
}
Comment on lines +400 to +407
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you test that it returns true on the new checkpoint obtained after applying this tx as well


#[test]
fn test_history_timestamps() {
let (block, _) = BlockContext::<Ethereum>::mocked();
let cp1 = block.start();
thread::sleep(Duration::from_millis(5));
let cp2 = cp1.barrier();
assert!(cp2.building_since() <= Instant::now());
assert!(cp2.building_since() >= cp1.created_at());
}
}