Skip to content

fix(ergotree-interpreter): reduce atLeast with degenerate bound instead of erroring#880

Open
mwaddip wants to merge 2 commits into
ergoplatform:developfrom
mwaddip:fix/atleast-degenerate-bound
Open

fix(ergotree-interpreter): reduce atLeast with degenerate bound instead of erroring#880
mwaddip wants to merge 2 commits into
ergoplatform:developfrom
mwaddip:fix/atleast-degenerate-bound

Conversation

@mwaddip

@mwaddip mwaddip commented Jun 4, 2026

Copy link
Copy Markdown

atLeast(bound, children) errored when bound > children.size or bound < 0. The JVM AtLeast.reduce (sigma/ast/trees.scala) reduces these to trivial props instead: bound <= 0 => TrueProp, bound > size => FalseProp (any bound, incl. > 255 — the 255 cap is a require on the child count, not the bound). The guards short-circuited before Cthreshold::reduce, which already encodes this; the reorder just lets it run, with the u8 conversion only on the valid 1 <= bound <= size path.

Found via a node syncing testnet: block 184,137 spends a V0 self-replicating contract evaluating atLeast(1, Coll[SigmaProp]()) (empty conditions) — must be FalseProp, not an error. Adds 3 regression tests.

mwaddip and others added 2 commits June 4, 2026 17:42
…ad of erroring

atLeast(bound, children) hard-errored when bound > children.size or bound < 0. The JVM AtLeast.reduce (sigma/ast/trees.scala) reduces these to trivial props: bound <= 0 => TrueProp, bound > size => FalseProp (for any bound, including > 255; the 255 limit is a require on the child count, not the bound). The error guards short-circuited before Cthreshold::reduce, which already encodes this. Reorder to mirror Scala; the u8 conversion now runs only on the valid 1 <= bound <= size path.

Wedged testnet sync at block 184,137: a V0 self-replicating contract spends with atLeast(1, Coll[SigmaProp]()) (empty conditions), which must reduce to FalseProp. Adds three regression tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…enerate bound

`CSigmaDslBuilder.atLeast` (sigma/data/CSigmaDslBuilder.scala) throws on more than
255 children (`MaxChildrenCountForAtLeastOp`) as its first statement, before
`AtLeast.reduce`. The cap therefore precedes the degenerate-bound short-circuits:
`atLeast(0, 256 props)` must error, not reduce to TrueProp. `ConcreteCollection`
carries a u16 count, so >255 children are wire-constructible and reachable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@mwaddip

mwaddip commented Jun 10, 2026

Copy link
Copy Markdown
Author

Folded in a closely-related conformance fix on the same op: the 255-children cap.

CSigmaDslBuilder.atLeast (CSigmaDslBuilder.scala) throws MaxChildrenCountForAtLeastOp = 255 as its first statement — before AtLeast.reduce, where the degenerate-bound arms this PR adds live. So the cap overrides the degenerate reductions: atLeast(0, 256 props) must error, not short-circuit to TrueProp. ConcreteCollection carries a u16 count, so >255 children are wire-constructible and reachable.

Added input.len() > 255 ⇒ error ahead of the bound arms, with a regression test (the 256-children rejects + the 255 cap-exclusive accept). The cap is exclusive (255 accepted); the bound itself stays uncapped.

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