Skip to content

Add stellar contract verify command#2586

Draft
fnando wants to merge 18 commits into
contract-build-verifiablefrom
contract-verify
Draft

Add stellar contract verify command#2586
fnando wants to merge 18 commits into
contract-build-verifiablefrom
contract-verify

Conversation

@fnando

@fnando fnando commented May 22, 2026

Copy link
Copy Markdown
Member

⚠️ Depends on #2585 — do not merge until #2585 lands on main. This PR's base is contract-build-verifiable, so once #2585 merges, GitHub will automatically retarget this one to main.

What

Adds a new stellar contract verify subcommand that takes a contract id (--id) or WASM hash (--wasm-hash) to fetch from the network, or a local WASM (--wasm) — the three are mutually exclusive. It reads the SEP-58 build metadata embedded in it (bldimg, source identification, build flags), re-runs the recorded build inside the recorded container image, and byte-compares the result against the original to confirm the WASM is reproducible.

Notable bits:

  • The WASM records source_sha256 (required) and, optionally, a source_uri. Verify fetches the source tarball from the recorded source_uri, or from a --source-uri override (an http(s) URL or a local file path), checks its SHA-256 against the recorded value, then extracts it. The source is always a content-addressed tarball, so there's no runtime dependency on a system git binary.
  • It reuses the --verifiable build machinery rather than reimplementing it: the same source-archive extraction (under the data dir, permission-hardened), the same container run, and the same --meta composition — so the rebuilt WASM's metadata matches the original byte-for-byte.
  • A trust prompt fires before pulling an unrecognized bldimg, and unconditionally for any tarball source (tarballs are never default-trusted). --trust skips it; the prompt overrides --quiet so it can't be silenced by accident. The default trust list is the stellar/stellar-cli image.
  • The materialized source directory is created with hardened permissions so a local attacker can't slip a file in mid-verify.
  • Integration tests cover the full loop without any network clone: scaffold with contract init, build verifiably, regenerate the matching archive with contract archive, verify it via --source-uri, plus verify-by---id and a tampered-bytes failure case. They live in the existing integration tier.

Why

#2585 makes it possible to produce a verifiable build; this PR is the other half — a way to check a deployed contract against its claimed source. Together they close the SEP-58 loop end-to-end in the CLI.

Known limitations

N/A

@github-project-automation github-project-automation Bot moved this to Backlog (Not Ready) in DevX May 22, 2026
@fnando fnando moved this from Backlog (Not Ready) to In Progress in DevX May 22, 2026
@fnando fnando self-assigned this May 22, 2026
@saimeunt

saimeunt commented Jun 5, 2026

Copy link
Copy Markdown

Hi @fnando, we just submitted a proposal for the Contract Source Verification Service RFP and it mentioned your draft PR.

It’s great that SEP-58 core verification logic is now embedded directly in stellar-cli, it provides a single source of truth for build reproducibility among verifiers. We plan to use stellar contract verify in our service to handle the actual verification, which includes fetching WASM, extracting metadata, rebuilding contract with the correct buildimg and comparing rebuilt WASM hash with on-chain hash.

While designing our tech architecture document for the RFP, we noticed retroactive verification is a mandatory requirement for the upcoming verification service, but contracts deployed before stellar contract build —-verifiable lack the proper contractmetav0 containing the SEP-58 fields expected by stellar contract verify.

At the moment, stellar contract verifywill error when SEP-58 fields are missing (as per WIP implementation). This means in its current state the core verification logic from stellar-cli can’t be leveraged to implement retroactive verification using the same ideal path as newly-deployed contracts built with with stellar contract build —-verifiable.

In your notable bits, you mention that the user can supply a local file or URL via --tarball-urlfor supplying tarball_url when it’s missing in contractmetav0, eg. when working with closed-source contracts. We think this should be extended to all SEP-58 fields to allow supporting a wider range of verifications scenario, providing an escape hatch for contracts deployed before SEP-58 is adopted.

It is the responsibility of the verifier to flag these verification results as having their build environment provided by the user submitting the verification and not recorded on-chain in WASM metadata.

Does this suggestion makes sense and do you plan to add support for user-supplied build environment + source identification parameters while finalizing this draft?

@fnando

fnando commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

@saimeunt Yes, the scenario makes sense, but I don't think it should live under stellar contract verify.

The way I see it, the verification service is the one responsible for receiving and storing everything needed to build the contract (source code, OS distro, build options, etc.). For that reason I'd keep the SEP-58 path in the CLI strictly tied to the immutable, on-chain contractmetav0, so its output means one specific, auditable thing, and have the service own its build+verification pipeline for everything else.

The real distinction isn't whether the build image is custom (an on-chain metadata can reference a custom image too, and that's equally hard to trust without auditing the image). It's chain of custody: on-chain fields are immutable and tied to the deployer, while user-supplied fields have no such provenance. That's exactly the case you raised; it's the verifier's responsibility to flag those results as "build environment provided by the submitter, not recorded on-chain."

I'd put all of that under out-of-band verification: the registry works with developers to verify contracts and covers everything SEP-58 doesn't (private source, pre-SEP-58 contracts1, etc.). The registry marks the contract verified, and it's ultimately up to users to trust the registry's findings, so the more verification services a developer goes through, the higher the trust.

Footnotes

  1. pre-SEP-58 contracts with public source are, hopefully, the easiest to handle in such a pipeline, especially if they weren't built with a cargo install-generated CLI, because matching distro + stellar-cli + rust + git revision + build opts will likely reproduce the same wasm 🤞.

@leighmcculloch

Copy link
Copy Markdown
Member

A verification service doesn't need to use the cli to verify with data not in the wasm meta. It should use the docker image directly.

@saimeunt

saimeunt commented Jun 8, 2026

Copy link
Copy Markdown

@fnando @leighmcculloch Thanks for your answers, I agree stellar-cli and the stellar contract verify command is strictly a developer-facing CLI that can be used to locally verify a contract and check against what verifiers report.

Verifiers will use their own logic built on top of the stellar-cli Docker image to actually verify contracts and support more scenarios than the standard SEP-58 path.

@fnando fnando force-pushed the contract-build-verifiable branch 2 times, most recently from 557647b to 6e7c125 Compare June 17, 2026 19:31
@fnando fnando force-pushed the contract-verify branch from 2f43fc9 to 70330f2 Compare June 17, 2026 22:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

3 participants