Repository navigation
fix(template): accept array covenant inputs in artifacts - #4
Conversation
arkadec emits bytes[3] for a bytes[N] function parameter. Parse it like a constructor array; refuse a template that would spend such a function, since the instance fills one stack item per input.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
WalkthroughArkade artifact parsing now accepts supported scalar array inputs. Template parsing returns ChangesArkade Array Inputs
Priority: ⬇️ Low Estimated code review effort: 2 (Simple) | ~10 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to
|
arkana-ai-bot
left a comment
There was a problem hiding this comment.
Review of fix(template): accept array covenant inputs in artifacts
Scope: pkg/template/artifact.go and pkg/template/template.go. No VTXO/signing/forfeit/round/exit paths are touched — this is template validation only.
Correctness
artifact.go:224 — validType(in.Type, nil) substitution
The replacement is sound. validType with structs=nil accepts exactly scalars and elementType[N] where elementType ∈ scalarTypes and 1 ≤ N ≤ maxArray(1024). The nil map lookup (structs[t]) returns false without panic in Go, so struct types are still rejected. Nested arrays (bytes[3][2]) are rejected because the first group of arrayType ([a-z0-9]+) cannot itself be an array expression — the regex enforces a single bracket pair.
template.go:539–542 — spend guard
Placement is correct: the check fires before the arity check, so a template referencing a function with any array covenant input gets ErrUnsupported regardless of how many arguments the template provides. The guard only runs when f.Arkade != nil (the want slice is only populated from f.Arkade.Inputs), so plain tapscript functions without covenants are unaffected.
Artifact ID stability
Artifacts already stored in the database had scalar-only covenant inputs (array types were unconditionally rejected before). This change does not alter IDs for any previously valid artifact. New artifacts containing bytes[N] covenant inputs hash correctly through d.json(), which round-trips the Type string verbatim.
Test coverage
TestParseArtifactArrayInput covers:
- Acceptance:
bytes[3]parses and the type is preserved inDefinition. - Rejection:
float[3](non-scalar element),bytes[0](zero index, rejected by regex),bytes[](empty index),bytes[3][2](nested),signature[3](signature not in scalarTypes).
TestArrayInputs covers:
- Template with array input on a non-spent function → parses OK.
- Template spending a function with an array input →
ErrUnsupportedwith the input name in the message.
Both success and failure paths are exercised. The error sentinel (ErrUnsupported) and message content are asserted.
Minor observations (non-blocking)
-
TestArrayInputsis index-dependent (fn=0,fn=1intoreleaseDoc'sfunctionsarray). IfreleaseDoc's function order ever changes, the test's intent silently inverts. A comment naming the function at each index would make this more robust, e.g.:// fn=0: timelockClaim (not spent by the template) // fn=1: nonInteractiveClaim (the function the template spends)
No correctness issue today.
-
"signature[3]"rejection is tested and correct (signatureis not inscalarTypes), but it is not possible to construct abytes[N]of signatures through the compiler anyway. The test is still valuable as a negative case. -
The PR description is accurate that filling arrays in the instance builder is out of scope here. If array filling is added later, the guard at
template.go:539–542is the right place to remove the restriction, and the comment in the error message already signals why it is there.
No protocol issues, no security issues, no cross-repo surface changes. The fix is minimal and correct.
The spent and unspent functions were addressed by index into releaseDoc, so reordering its functions would silently swap what each half of the test checks.
|
Thanks @arkana-ai-bot. cc0b7c1 picks the two functions by name ( |
|
Confirmed — cc0b7c1 resolves observation #1 cleanly. The helper now iterates by |
arkana-ai-bot
left a comment
There was a problem hiding this comment.
Follow-up pass — 1 commit since a1766ec (cc0b7c1, test-only). 1/1 prior observations fixed; 0 remain.
Prior-issue closure
Observation #1 — index-dependent function selection in TestArrayInputs → Fixed in cc0b7c1.
The withInput helper was changed from fn int (a positional index into releaseDoc.functions) to name string. It now iterates def["functions"] by the "name" key, injects the bytes[3] input onto the matching entry, and calls t.Fatalf("releaseDoc has no function %q", name) if neither "exit" nor "release" is found. Any future reordering or renaming of releaseDoc's functions now produces an explicit, descriptive test failure rather than a silent test-intent swap. The t.Fatalf inside the edited closure terminates the test goroutine correctly.
Observation #2 — "signature[3]" negative case → No longer applicable (informational note; no code change warranted).
Observation #3 — future array-fill removal point → No longer applicable (architectural note; no change warranted).
Incremental diff assessment
Only pkg/template/template_test.go changed. No production code, no protocol paths, no public API surface. The fix is correct and minimal.
No new findings.
Artifacts whose functions take an array covenant input are refused at registration with
unsupported arkade input type "bytes[3]". arkadec emits that type for abytes[N]function parameter, for example three signatures for an N-of-N release. So a contract that uses one cannot be watched at all, even when the watch only spends a function that takes no inputs, likereneworcomplete.This parses covenant input types the same way constructor inputs are already parsed: through
validType, a scalar element with a size up tomaxArray. A template that would spend a function taking an array input is now refused withErrUnsupported, because the instance builder fills one stack item per input and does not flatten arrays. Nothing changes for templates that work today. If you'd rather support filling arrays instead of refusing, I'm happy to take it that way.I hit this watching Portcullis vaults: their
releaseandunvaultfunctions takebytes[3]signature arrays, whilerenewandcompletetake none.TestParseArtifactArrayInputcovers the accepted and refused types.TestArrayInputscovers a template next to a function with an array input (it parses) and a template spending that function (ErrUnsupported).go testpasses inpkg/templateand in the root module's packages that don't need Postgres; I had no database locally for the Postgres-backed suites.Summary by CodeRabbit