Skip to content

The record half of the candidate anchor can still be spelled type(X).creationCode #41

Description

@thedavidmeister

What

The mirror of #34, in the other direction, and not closed by the fix for it.

#34 was that a candidate's SOURCE operand could be pointed at the snapshot constant,
making checkCandidatesAnchoredToSource compare a value with itself.
rainlanguage/rain.deploy#242 fixes that by removing
DeployCandidate.sourceCreationCode and reading the source operand from
vm.getCode(artifactPath) — the compiler's answer, which a consumer cannot supply.

The RECORD operand is still consumer-supplied. DeploySuite.creationCode can be
spelled type(X).creationCode instead of the generated CREATION_CODE constant,
which puts both operands back on the source side. The anchor then compares the
compiler's output against the compiler's output and is satisfied for any contract,
whatever the frozen snapshot on disk actually records.

Why rain-deploy cannot catch it

Symmetrically to #34: while the snapshot and current source agree — the normal
committed state — type(X).creationCode and the generated CREATION_CODE constant
are the same bytes. They diverge only once the snapshot goes stale, which is exactly
the moment the anchor is supposed to fire. No runtime value assertion inside
rain-deploy can distinguish the two spellings.

DeploySuite.creationCode's own NatSpec already warns about this. rain.deploy
catches it for ITSELF with an AST test
(RegistryDeploySuitesTest.testCandidatesRecordTheGeneratedConstants) that inspects
how the literal is spelled — a test consumers do not inherit.

Consequence

A consumer that makes this edit has a candidate whose pins are unanchored in both
directions while every check stays green, including the one
RainDeployBroadcast.run() runs before it broadcasts.

This repo is not currently in that state: its candidate records
CLONE_FACTORY_CREATION_CODE_CANDIDATE, and
LibCloneFactoryDeployCandidateTest.testCandidateCreationCodeMatchesSource compares
the generated constant to type(CloneFactory).creationCode directly. That test is
this repo's own and is not something rain-deploy guarantees a consumer has.

Directions (for triage, not a recommendation)

Provenance

Surfaced while fixing #34; see rainlanguage/rain.deploy#242, which names this as a
residual hazard it does not close.


Found by adversarial mutation testing (skill 0.35.0).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    adversarialFound by the adversarial half of a mutation-test scanauditFinding from an audit or mutation-test scan

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions