{"record":{"id":"546ba25f005bc94f","repo":"nautechsystems/nautilus_trader","slug":"rpc-positions-do-not-match-the-complete-hypersync","errorCode":null,"errorMessage":"RPC positions do not match the complete HyperSync topology: expected {} positions, received {}","messagePattern":"RPC positions do not match the complete HyperSync topology: expected (.+?) positions, received (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/data/core.rs","lineNumber":2113,"sourceCode":"                    position.liquidity,\n                )\n            })\n            .collect();\n        let actual_positions: AHashMap<_, _> = snapshot\n            .positions\n            .iter()\n            .map(|position| {\n                (\n                    (position.owner, position.tick_lower, position.tick_upper),\n                    position.liquidity,\n                )\n            })\n            .collect();\n\n        if actual_positions.len() != snapshot.positions.len()\n            || actual_positions != expected_positions\n        {\n            anyhow::bail!(\n                \"RPC positions do not match the complete HyperSync topology: expected {} positions, received {}\",\n                expected_positions.len(),\n                actual_positions.len()\n            );\n        }\n\n        let actual_ticks: AHashMap<_, _> = snapshot\n            .ticks\n            .iter()\n            .map(|tick| (tick.value, tick))\n            .collect();\n\n        if actual_ticks.len() != snapshot.ticks.len() {\n            anyhow::bail!(\"RPC snapshot contains duplicate ticks\");\n        }\n\n        let expected_tick_values = profiler.get_active_tick_values();\n        if actual_ticks.len() != expected_tick_values.len() {","sourceCodeStart":2095,"sourceCodeEnd":2131,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/data/core.rs#L2095-L2131","documentation":"After replaying HyperSync events and fetching the on-chain RPC snapshot, validate_rpc_snapshot_topology asserts the RPC-returned positions exactly equal the positions derived from event replay (same owner/tick-range keys and liquidity). A mismatch means event replay and on-chain state disagree, so the snapshot is rejected rather than restored.","triggerScenarios":"construct_pool_profiler_from_hypersync_rpc calls validate_rpc_snapshot_topology and the fetched snapshot's position set differs from profiler.get_all_positions() — counts differ, keys differ, or (implied by the len check) duplicate position keys collapse in the map.","commonSituations":"Missed or malformed Mint/Burn logs during HyperSync replay (gaps in stream coverage); using a non-archive or reorg-affected RPC block for the snapshot; replaying from a wrong from_block so some liquidity events were never processed; a pool with liquidity events between the replay target block and the RPC query block.","solutions":["Compare expected vs received counts and find the missing/extra positions; verify HyperSync stream coverage from pool creation_block (or from_position) to to_block with no gaps.","Re-run bootstrap to a stable, recent block and with an archive-capable RPC to rule out reorgs or non-archive state misses.","Check that mint/burn event signatures in the DEX config match the pool's actual contract so no liquidity events are dropped as unexpected.","If new DEX variants emit extra liquidity-affecting events, extend process_pool_mint_event/burn handling so replay state includes them."],"exampleFix":"// before\nlet from_block = from_position.map_or(profiler.pool.creation_block, |block_position| block_position.number);\n// after (ensure full-history replay when topology validation fails)\nlet from_block = from_position\n    .filter(|bp| profiler.is_initialized)\n    .map_or(profiler.pool.creation_block, |block_position| block_position.number);","handlingStrategy":"retry","validationCode":"// Pre-check: replay from the pool's creation block so no liquidity events are missed\nlet from_block = from_position.filter(|_| profiler.is_initialized)\n    .map_or(pool.creation_block, |bp| bp.number);\nanyhow::ensure!(from_block <= pool.creation_block || profiler.is_initialized,\n    \"replay start {} may skip events; topology validation would fail\", from_block);","typeGuard":null,"tryCatchPattern":"match attempt_bootstrap(from_position).await {\n    Err(e) if e.to_string().contains(\"do not match the complete HyperSync topology\") => {\n        // retry once with full replay from pool.creation_block\n        attempt_bootstrap(None).await\n    }\n    other => other,\n}","preventionTips":["Use archive-capable RPC endpoints for historical snapshot blocks.","Ensure HyperSync stream coverage has no block gaps from from_block to to_block.","Verify DEX mint/burn signature configs match the actual pool contract's events.","Re-run bootstrap after detected chain reorgs."],"tags":["validation","rpc","hypersync","state-mismatch"],"backgroundTag":"schema-validation-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}