Skip to content

fix: resolve data loss bugs in farm IP, node interface, and contract mapping handlers#209

Open
sameh-farouk wants to merge 1 commit intomaster-automate-typegenfrom
master-fix-mapping-bugs
Open

fix: resolve data loss bugs in farm IP, node interface, and contract mapping handlers#209
sameh-farouk wants to merge 1 commit intomaster-automate-typegenfrom
master-fix-mapping-bugs

Conversation

@sameh-farouk
Copy link
Copy Markdown
Member

@sameh-farouk sameh-farouk commented Mar 31, 2026

Summary

Closes #208

Fixes 7 data corruption bugs in the event mapping handlers, discovered during a code audit.

Fixes

B1 — Race conditions in farmUpdated (farms.ts)
Replace async/await inside .forEach() with for...of loops for both IP save and IP removal iterations. Ensures sequential execution of read-modify-write operations.

B2 — PublicIp ID collision in farmStored (farms.ts)
Multiple public IPs in a FarmStored event all received the same ID (item.event.id), causing upsert overwrites. Now appends -{ip} to create unique IDs per IP.

B3 — Interfaces ID collision in nodeStored (nodes.ts)
Same collision pattern — multiple interfaces got the same ID. Now appends -{name}, matching the existing correct pattern in nodeUpdated.

B4 — Undefined contractID guard in grace period handlers (contracts.ts)
contractGracePeriodStarted and contractGracePeriodEnded had no guard when the event version was unrecognized. Added undefined check with error log and early return.

B5 — handlePublicConfigV105 fallthrough (nodes.ts)
When config was None (meaning "remove public config") and no existing record was found, the function fell through and created a ghost PublicConfig with all-null fields. Now returns early for the entire !config branch.

B6 — nodeStored never saved inline PublicConfig (nodes.ts)
In spec v9, create_node accepted a public_config parameter. getNodePublicConfig() extracted it but the result was never persisted. Now saves when non-null.

B7 — Cross-farm duplicate IP not actually skipped (farms.ts)
When an IP already existed on a different farm, the code logged "skipped" but continued to save — overwriting the original farm's gateway. Now properly continues after the error log. Also removed the no-op savedIP.ip reassignment.

Additional cleanup

  • Added - separator to composite IDs for readability (eventId-eth0 instead of eventIdeth0)
  • Applied separator consistently to both nodeStored and nodeUpdated interface IDs
  • Fixed typo "skiped" → "skipped" in error log

Backwards compatibility

  • All entity lookups use domain fields (ip, contractId, farm.id, node.nodeID), never the raw id — ID format changes are safe
  • ctx.store.save() is an upsert (INSERT ... ON CONFLICT (id) DO UPDATE) — confirmed in Subsquid's @subsquid/typeorm-store
  • Verified against tfchain pallet source: spec v9 (pallet 0.1.0-b1) accepted public_config in create_node; spec 11+ (pallet 0.1.0-b4) hardcoded None
  • Chain does not validate IP uniqueness across farms (add_farm_ip only checks within same farm)

Test plan

  • npx tsc --noEmit — compiles clean after each fix
  • Create farm with multiple IPs on devnet → verify all IPs visible in GraphQL
  • Create node with multiple interfaces → verify all interfaces visible
  • Full re-index from genesis → compare results before and after

…mapping handlers

- B1: Replace async forEach with for...of in farmUpdated to fix race conditions on IP saves/removals
- B2: Append IP string to PublicIp ID in farmStored/farmUpdated to prevent overwrites when multiple IPs exist
- B3: Append interface name to Interfaces ID in nodeStored (matching nodeUpdated pattern) to prevent overwrites
- B4: Add undefined guard for contractID in grace period handlers to prevent unpredictable queries
- B5: Fix handlePublicConfigV105 fallthrough creating ghost PublicConfig with null fields when config is undefined
- B6: Save inline PublicConfig in nodeStored for spec v9 nodes that carried publicConfig at creation time
- Fix cross-farm duplicate IP handling: properly skip instead of silently overwriting gateway
- Add '-' separator to composite IDs for readability (interfaces and public IPs)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sameh-farouk sameh-farouk force-pushed the master-automate-typegen branch from f97b850 to 94fdaf4 Compare April 6, 2026 14:43
@sameh-farouk sameh-farouk force-pushed the master-fix-mapping-bugs branch from bab6f37 to b2e5f55 Compare April 6, 2026 14:43
@sameh-farouk
Copy link
Copy Markdown
Member Author

sameh-farouk commented Apr 7, 2026

Total PublicIPs: Increased from 1,364 to 1,367 (+3)

  • collision fixes

    • Farm 4432: Increased from 4 to 6 IPs (+2). We recovered 1.1.1.{1,2}/24, bringing the count in line with the 6 IPs found on-chain.

    • Farm 7944: Increased from 1 to 2 IPs (+1). We recovered 98.2.88.99/24. The test now matches the 2 IPs (98.2.88.99/24 and 98.2.88.89/24) found on-chain.

  • cross-farm duplicate handling

    • Farm 4291: Decreased from 52 to 47 IPs (-5). It lost 125.25.25.{13,14,15}/16 (which belongs to farm 2586) and 1.1.1.{1,2}/24 (which belongs to farm 4432). These were previously present only because collision overwrites assigned IPs to whichever farm was processed last.

    • Farm 2586: Increased from 15 to 20 IPs (+5). We recovered 125.25.25.{11,12,13,14,15}/16. While there are 21 IPs on-chain, 125.25.25.25/16 was correctly skipped as it is already registered to farm 4376.

The fixed logic ensures the first farm keeps ownership while subsequent duplicates are logged and skipped. This match what was documnted, loged, and comunicated but it was broken.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Multiple data corruption bugs in event mapping handlers

1 participant