Skip to content

Fix store undo corruption on DELETE and bigdecimal min/max size inflation#819

Draft
sduchesneau wants to merge 2 commits into
developfrom
fix/store-undo-and-merge-size
Draft

Fix store undo corruption on DELETE and bigdecimal min/max size inflation#819
sduchesneau wants to merge 2 commits into
developfrom
fix/store-undo-and-merge-size

Conversation

@sduchesneau

Copy link
Copy Markdown
Contributor

Two independent store-integrity bugs in storage/store:

Fix 1: ApplyDeltasReverse aborted on first DELETE delta (storage/store/delta.go)

The reverse loop's StoreDelta_DELETE case ended with return, so reversing a block's deltas stopped at the first DELETE encountered (iterating backwards), leaving all earlier CREATE/UPDATE/DELETE deltas of that block unreverted. Any chain reorg (StepUndostoresHandleUndo) over a block containing a DELETE therefore silently and permanently corrupted the store. The return is removed so the loop reverses every delta.

Fix 2: totalSizeBytes inflation in bigdecimal min/max merge (storage/store/merge.go:281,359)

The MAX and MIN merge branches for bigfloat/bigdecimal called setNewKV for keys that already exist. setNewKV adds len(key)+len(value) without subtracting the previous value's size, so every squash inflated totalSizeBytes, eventually tripping a spurious "store above max size" deterministic failure. Switched to setKV (which adjusts for the previous value), matching what every other value type already does.

Tests

  • TestApplyDeltasReverse (storage/store/delta_test.go): applies [CREATE k1, UPDATE k2, DELETE k3, DELETE k4] then reverses, asserting the full original state (kv and totalSizeBytes) is restored. Fails before the fix, passes after.
  • TestStore_Merge_TotalSizeBytes (storage/store/merge_test.go): min and max bigdecimal stores merged twice over existing keys, asserting totalSizeBytes always equals the actual kv content size and does not grow on same-size updates. Fails before the fix, passes after.
  • Full go test ./storage/store/... ./pipeline/... passes.

🤖 Generated with Claude Code

ApplyDeltasReverse returned from the reverse loop on the first
DELETE delta, leaving all earlier deltas of the block unreverted
and the store silently corrupted after a chain reorg.
The bigdecimal max/min merge branches used setNewKV on keys that
already exist, adding key+value size without subtracting the
previous value, so totalSizeBytes grew on every squash and could
spuriously trip the max-store-size deterministic failure.
@sduchesneau

Copy link
Copy Markdown
Contributor Author

🔍 Vulnerabilities of ghcr.io/streamingfast/substreams:056122b

📦 Image Reference ghcr.io/streamingfast/substreams:056122b
digestsha256:c14e42d86f1b5f330d988a6ff4c76d26090b86708600bb26c9d4465802ce4017
vulnerabilitiescritical: 0 high: 0 medium: 0 low: 0
platformlinux/amd64
size108 MB
packages353
📦 Base Image ubuntu:24.04
also known as
  • noble
  • noble-20260610
digestsha256:52df9b1ee71626e0088f7d400d5c6b5f7bb916f8f0c82b474289a4ece6cf3faf
vulnerabilitiescritical: 0 high: 0 medium: 12 low: 5

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.

1 participant