@@ -1667,6 +1667,93 @@ impl ApiTester {
1667
1667
self
1668
1668
}
1669
1669
1670
+ /// Test fetching of blob sidecars that are not available in the database due to pruning.
1671
+ ///
1672
+ /// If `zero_blobs` is false, test a block with >0 blobs, which should be unavailable.
1673
+ /// If `zero_blobs` is true, then test a block with 0 blobs, which should still be available.
1674
+ pub async fn test_get_blob_sidecars_pruned ( self , zero_blobs : bool ) -> Self {
1675
+ // Prune all blobs prior to the database's split epoch.
1676
+ let store = & self . chain . store ;
1677
+ let split_epoch = store. get_split_slot ( ) . epoch ( E :: slots_per_epoch ( ) ) ;
1678
+ let force_prune = true ;
1679
+ self . chain
1680
+ . store
1681
+ . try_prune_blobs ( force_prune, split_epoch)
1682
+ . unwrap ( ) ;
1683
+
1684
+ let oldest_blob_slot = store. get_blob_info ( ) . oldest_blob_slot . unwrap ( ) ;
1685
+
1686
+ assert_ne ! (
1687
+ oldest_blob_slot, 0 ,
1688
+ "blob pruning should have pruned some blobs"
1689
+ ) ;
1690
+
1691
+ // Find a block with either 0 blobs or 1+ depending on the value of `zero_blobs`.
1692
+ let mut test_slot = None ;
1693
+ for slot in 0 ..oldest_blob_slot. as_u64 ( ) {
1694
+ let block_id = BlockId ( CoreBlockId :: Slot ( Slot :: new ( slot) ) ) ;
1695
+ let ( block, _, _) = block_id. blinded_block ( & self . chain ) . unwrap ( ) ;
1696
+ let num_blobs = block. num_expected_blobs ( ) ;
1697
+
1698
+ if ( zero_blobs && num_blobs == 0 ) || ( !zero_blobs && num_blobs > 0 ) {
1699
+ test_slot = Some ( Slot :: new ( slot) ) ;
1700
+ break ;
1701
+ }
1702
+ }
1703
+ let test_slot = test_slot. expect ( & format ! (
1704
+ "should be able to find a block matching zero_blobs={zero_blobs}"
1705
+ ) ) ;
1706
+
1707
+ match self
1708
+ . client
1709
+ . get_blobs :: < E > ( CoreBlockId :: Slot ( test_slot) , None )
1710
+ . await
1711
+ {
1712
+ Ok ( result) => {
1713
+ if zero_blobs {
1714
+ assert_eq ! (
1715
+ & result. unwrap( ) . data[ ..] ,
1716
+ & [ ] ,
1717
+ "empty blobs are always available"
1718
+ ) ;
1719
+ } else {
1720
+ assert_eq ! ( result, None , "blobs should have been pruned" ) ;
1721
+ }
1722
+ }
1723
+ Err ( e) => panic ! ( "failed with non-404 status: {e:?}" ) ,
1724
+ }
1725
+
1726
+ self
1727
+ }
1728
+
1729
+ pub async fn test_get_blob_sidecars_pre_deneb ( self ) -> Self {
1730
+ let oldest_blob_slot = self . chain . store . get_blob_info ( ) . oldest_blob_slot . unwrap ( ) ;
1731
+ assert_ne ! (
1732
+ oldest_blob_slot, 0 ,
1733
+ "oldest_blob_slot should be non-zero and post-Deneb"
1734
+ ) ;
1735
+ let test_slot = oldest_blob_slot - 1 ;
1736
+ assert ! (
1737
+ !self
1738
+ . chain
1739
+ . spec
1740
+ . fork_name_at_slot:: <E >( test_slot)
1741
+ . deneb_enabled( ) ,
1742
+ "Deneb should not be enabled at {test_slot}"
1743
+ ) ;
1744
+
1745
+ match self
1746
+ . client
1747
+ . get_blobs :: < E > ( CoreBlockId :: Slot ( test_slot) , None )
1748
+ . await
1749
+ {
1750
+ Ok ( result) => panic ! ( "queries for pre-Deneb slots should fail. got: {result:?}" ) ,
1751
+ Err ( e) => assert_eq ! ( e. status( ) . unwrap( ) , 400 ) ,
1752
+ }
1753
+
1754
+ self
1755
+ }
1756
+
1670
1757
pub async fn test_beacon_blocks_attestations ( self ) -> Self {
1671
1758
for block_id in self . interesting_block_ids ( ) {
1672
1759
let result = self
@@ -6846,6 +6933,36 @@ async fn get_blob_sidecars() {
6846
6933
. await ;
6847
6934
}
6848
6935
6936
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
6937
+ async fn get_blob_sidecars_pruned ( ) {
6938
+ let mut config = ApiTesterConfig :: default ( ) ;
6939
+ config. spec . altair_fork_epoch = Some ( Epoch :: new ( 0 ) ) ;
6940
+ config. spec . bellatrix_fork_epoch = Some ( Epoch :: new ( 0 ) ) ;
6941
+ config. spec . capella_fork_epoch = Some ( Epoch :: new ( 0 ) ) ;
6942
+ config. spec . deneb_fork_epoch = Some ( Epoch :: new ( 0 ) ) ;
6943
+
6944
+ ApiTester :: new_from_config ( config)
6945
+ . await
6946
+ . test_get_blob_sidecars_pruned ( false )
6947
+ . await
6948
+ . test_get_blob_sidecars_pruned ( true )
6949
+ . await ;
6950
+ }
6951
+
6952
+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
6953
+ async fn get_blob_sidecars_pre_deneb ( ) {
6954
+ let mut config = ApiTesterConfig :: default ( ) ;
6955
+ config. spec . altair_fork_epoch = Some ( Epoch :: new ( 0 ) ) ;
6956
+ config. spec . bellatrix_fork_epoch = Some ( Epoch :: new ( 0 ) ) ;
6957
+ config. spec . capella_fork_epoch = Some ( Epoch :: new ( 0 ) ) ;
6958
+ config. spec . deneb_fork_epoch = Some ( Epoch :: new ( 1 ) ) ;
6959
+
6960
+ ApiTester :: new_from_config ( config)
6961
+ . await
6962
+ . test_get_blob_sidecars_pre_deneb ( )
6963
+ . await ;
6964
+ }
6965
+
6849
6966
#[ tokio:: test( flavor = "multi_thread" , worker_threads = 2 ) ]
6850
6967
async fn post_validator_liveness_epoch ( ) {
6851
6968
ApiTester :: new ( )
0 commit comments