fix(consensus): structure-delimit the nested SBox-constant inner tree skip - #124
Conversation
… skip Following #123 (which made the top-level size-delimited ErgoTree parse structure-delimited), the nested `SBox`-constant path still skipped its inner size-delimited tree by the DECLARED size: `skip_ergo_tree` read `size` and did `get_bytes(size)`. Scala deserializes a nested box's proposition INLINE via `ErgoTreeSerializer.deserializeErgoTree` (`ErgoBoxCandidate.parseBody`), which is structure-delimited — the declared size does not bound the parse or advance the reader, which is left at the actual body end where the box's `creationHeight` is read next. So for any nested box whose declared tree size ≠ its body length (adversarial-only, but the same reject-valid / accept-invalid class as #123), the node consumed the wrong number of bytes and desynced the box (and the enclosing tree's parse). Rewind to before the header and delegate to `read_ergo_tree_tracking_wrap`, which (since #123) parses the inner tree structurally, advances the reader by the true body length on success or to Scala's `numBytes` boundary on a soft-fork wrap, forwards the inner tree's group elements onto the outer reader (the JVM curve-checks an off-curve point inside a nested box while deserializing it), and re-raises `DepthLimitExceeded` / `HardReject` so they escape the enclosing tree's wrap. `check_tree_version_supported` still hard-rejects a future-version inner tree afterward. The box stays opaque for round-trip via the caller's preserved bytes; only the reader advance moves. The sizeless nested path (`parse_sizeless_inner_box_script` + `harden_sizeless_inner_error`) is unchanged. New `skip_ergo_tree_size_delimited_advances_by_body_not_declared_size` test pins the structural advance (a size-5 / body-2 tree followed by trailing box bytes advances by 2, leaving the 3 trailing bytes). The existing nested-box v6 / rule-1012 / version tests still pass (4400 green). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughIn skip_ergo_tree size-delimited fix and regression test
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
✅ Action performedReview finished.
|
What
A follow-up to #123 (structure-delimited top-level size parse), applying the same fix to the
nested
SBox-constant path.skip_ergo_treestill skipped a nested box's size-delimited innertree by the declared size (
get_bytes(size)). Scala deserializes a nested box's propositioninline via
ErgoTreeSerializer.deserializeErgoTree(ErgoBoxCandidate.parseBody), which isstructure-delimited — it leaves the reader at the actual body end, where
creationHeightisread next. So for any nested box whose declared tree size ≠ its body length (adversarial-only, same
reject-valid / accept-invalid class as #123), the node consumed the wrong number of bytes and
desynced the box and the enclosing tree's parse.
How
Rewind to before the header
skip_ergo_treealready read, and delegate toread_ergo_tree_tracking_wrap— which (since #123) parses the inner tree structurally, advances thereader by the true body length on success or to Scala's
numBytesboundary on a soft-fork wrap,forwards the inner tree's group elements onto the outer reader (the JVM curve-checks an off-curve
point inside a nested box), and re-raises
DepthLimitExceeded/HardRejectso they escape theenclosing tree's wrap.
check_tree_version_supportedstill hard-rejects a future-version inner treeafterward. The sizeless nested path (
parse_sizeless_inner_box_script+harden_sizeless_inner_error)is intentionally unchanged.
Validation
Reviewed source-level against the Scala reference (no substantive issues): the success / soft-wrap
cursor positions, GE forwarding (no double-count), and the nested error classes — non-SigmaProp root
→ wrap, pre-v3 v6 method → wrap, version > max → hard-reject, over-depth → escape — all match Scala.
New
skip_ergo_tree_size_delimited_advances_by_body_not_declared_sizepins the structural advance(a size-5 / body-2 inner tree followed by trailing box bytes advances by 2, leaving the 3 trailing
bytes). The existing nested-box v6 / rule-1012 / version tests still pass.
Test plan
🤖 Generated with Claude Code
Summary by CodeRabbit