Skip to content

Commit 10cd5f4

Browse files
authored
fix: stop requesting all snapshots everytime there is an update (#848)
2 parents 3b67654 + 9409de5 commit 10cd5f4

File tree

1 file changed

+107
-1
lines changed

1 file changed

+107
-1
lines changed

tycho-client/src/feed/synchronizer.rs

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)