Skip to content

Commit ffcb132

Browse files
shardtree: truncate exactly at an achievable boundary, never retaining data beyond the cut
truncate_to_checkpoint_internal swallowed the None that LocatedPrunableTree::truncate_to_position returns when the requested position falls inside a pruned hash leaf or a Nil region: shards, cap, and checkpoints were all left untouched while the call reported success. A caller that truncates after a chain reorg then re-inserts recomputed subtrees over the retained stale hashes, and insert_subtree fails with InsertionError::Conflict at the stale address, deterministically and forever. Truncation at a position inside a pruned region is not representable: a single pruned hash commits to data on both sides of the cut. Truncation is now total and honest instead: any node committing to data beyond the cut is discarded, the boundary retreats to the position immediately preceding the discarded node's range, cached annotations along the cut path are cleared, shards and cap are truncated at the same achieved boundary, checkpoints are always truncated, and checkpoints recording positions beyond the achieved boundary (including the truncation target itself) are removed. truncate_to_checkpoint and truncate_to_checkpoint_depth report the achieved TreeState so callers can re-insert data beyond the boundary, e.g. by rescanning the chain from the achieved state.
1 parent 7b23adb commit ffcb132

4 files changed

Lines changed: 563 additions & 89 deletions

File tree

shardtree/CHANGELOG.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,27 @@ and this project adheres to Rust's notion of
4444
within a single pruning window.
4545

4646

47+
### Changed
48+
- `shardtree::ShardTree::{truncate_to_checkpoint, truncate_to_checkpoint_depth}`
49+
now return `Result<Option<shardtree::store::TreeState>, ...>` instead of
50+
`Result<bool, ...>`. `None` replaces `false` (no such checkpoint); `Some`
51+
reports the tree state actually achieved, which may be earlier than the
52+
checkpointed position if pruning prevents an exact truncation. In that case
53+
checkpoints beyond the achieved state (including the requested one) are
54+
removed, and the caller must restore the missing range, e.g. by rescanning.
55+
- `shardtree::LocatedPrunableTree::truncate_to_position` now returns
56+
`(Self, Option<Position>)` instead of `Option<Self>`. Truncation always
57+
succeeds, retreating the boundary when pruning prevents an exact cut; the
58+
returned position is the boundary actually achieved. Parent annotations
59+
committing to discarded data are now also discarded.
60+
61+
### Fixed
62+
- `shardtree::ShardTree::{truncate_to_checkpoint, truncate_to_checkpoint_depth}`
63+
no longer silently leave the tree unmodified when the checkpointed position
64+
falls within a pruned node. The stale retained hashes previously caused
65+
persistent `InsertionError::Conflict` failures when re-inserting subtree
66+
data after a chain reorg.
67+
4768
## [0.6.2] - 2026-02-20
4869

4970
### Added

0 commit comments

Comments
 (0)