@@ -319,10 +319,19 @@ where
319319 . into_iter ( )
320320 . collect ( ) ;
321321
322+ // Filter components to only include the requested ones
323+ let filtered_components: HashMap < _ , _ > = self
324+ . component_tracker
325+ . components
326+ . iter ( )
327+ . filter ( |( id, _) | component_ids. contains ( id) )
328+ . map ( |( k, v) | ( k. clone ( ) , v. clone ( ) ) )
329+ . collect ( ) ;
330+
322331 let request = SnapshotParameters :: new (
323332 self . extractor_id . chain ,
324333 & self . extractor_id . name ,
325- & self . component_tracker . components ,
334+ & filtered_components ,
326335 & contract_ids,
327336 header. number ,
328337 )
@@ -1293,6 +1302,103 @@ mod test {
12931302 assert_eq ! ( snap, exp) ;
12941303 }
12951304
1305+ /// Test that get_snapshots only fetches snapshots for requested components,
1306+ /// not all tracked components. This prevents returning full snapshots repeatedly
1307+ /// when only a subset of components need updates.
1308+ #[ test_log:: test( tokio:: test) ]
1309+ async fn test_get_snapshots_filters_to_requested_components_only ( ) {
1310+ let header = BlockHeader :: default ( ) ;
1311+ let mut rpc = make_mock_client ( ) ;
1312+
1313+ // Create three components
1314+ let component1 = ProtocolComponent { id : "Component1" . to_string ( ) , ..Default :: default ( ) } ;
1315+ let component2 = ProtocolComponent { id : "Component2" . to_string ( ) , ..Default :: default ( ) } ;
1316+ let component3 = ProtocolComponent { id : "Component3" . to_string ( ) , ..Default :: default ( ) } ;
1317+
1318+ let component2_clone = component2. clone ( ) ;
1319+
1320+ // Mock the RPC call and verify it only receives Component2
1321+ rpc. expect_get_snapshots ( )
1322+ . withf (
1323+ |request : & SnapshotParameters ,
1324+ _chunk_size : & Option < usize > ,
1325+ _concurrency : & usize | {
1326+ // Verify that the request contains ONLY Component2, not all tracked components
1327+ request. components . len ( ) == 1 &&
1328+ request
1329+ . components
1330+ . contains_key ( "Component2" )
1331+ } ,
1332+ )
1333+ . times ( 1 )
1334+ . returning ( move |_request, _chunk_size, _concurrency| {
1335+ Ok ( Snapshot {
1336+ states : [ (
1337+ "Component2" . to_string ( ) ,
1338+ ComponentWithState {
1339+ state : ResponseProtocolState {
1340+ component_id : "Component2" . to_string ( ) ,
1341+ ..Default :: default ( )
1342+ } ,
1343+ component : component2_clone. clone ( ) ,
1344+ entrypoints : vec ! [ ] ,
1345+ component_tvl : None ,
1346+ } ,
1347+ ) ]
1348+ . into_iter ( )
1349+ . collect ( ) ,
1350+ vm_storage : HashMap :: new ( ) ,
1351+ } )
1352+ } ) ;
1353+
1354+ rpc. expect_get_traced_entry_points ( )
1355+ . returning ( |_| {
1356+ Ok ( TracedEntryPointRequestResponse {
1357+ traced_entry_points : HashMap :: new ( ) ,
1358+ pagination : PaginationResponse :: new ( 0 , 20 , 0 ) ,
1359+ } )
1360+ } ) ;
1361+
1362+ let mut state_sync = with_mocked_clients ( true , false , Some ( rpc) , None ) ;
1363+
1364+ // Track all three components
1365+ state_sync
1366+ . component_tracker
1367+ . components
1368+ . insert ( "Component1" . to_string ( ) , component1. clone ( ) ) ;
1369+ state_sync
1370+ . component_tracker
1371+ . components
1372+ . insert ( "Component2" . to_string ( ) , component2. clone ( ) ) ;
1373+ state_sync
1374+ . component_tracker
1375+ . components
1376+ . insert ( "Component3" . to_string ( ) , component3. clone ( ) ) ;
1377+
1378+ // Request snapshot for ONLY Component2
1379+ let components_arg = [ "Component2" . to_string ( ) ] ;
1380+
1381+ let snap = state_sync
1382+ . get_snapshots ( header. clone ( ) , Some ( & components_arg) )
1383+ . await
1384+ . expect ( "Retrieving snapshot failed" ) ;
1385+
1386+ // Verify we only got Component2 back
1387+ assert_eq ! ( snap. snapshots. states. len( ) , 1 ) ;
1388+ assert ! ( snap
1389+ . snapshots
1390+ . states
1391+ . contains_key( "Component2" ) ) ;
1392+ assert ! ( !snap
1393+ . snapshots
1394+ . states
1395+ . contains_key( "Component1" ) ) ;
1396+ assert ! ( !snap
1397+ . snapshots
1398+ . states
1399+ . contains_key( "Component3" ) ) ;
1400+ }
1401+
12961402 fn mock_clients_for_state_sync ( ) -> ( MockRPCClient , MockDeltasClient , Sender < BlockChanges > ) {
12971403 let mut rpc_client = make_mock_client ( ) ;
12981404 // Mocks for the start_tracking call, these need to come first because they are more
0 commit comments