paritytech / paritytech/contract-dependency-manager

Rust version pinning: cdm::import! calls execute latest — needs a CallBuilder calldata preamble upstream

Open
#80 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
4
Forks
3
Avg merge
4d 13h
Merged PRs (30d)
3

Description

Problem

Since #76, cdm.json pins an exact version per dependency and cdm::import! generates type-safe stubs from that version's exact ABI — but the generated calls go out as plain calldata, which the per-name proxy routes to the latest implementation. Rust consumers today get "pinned ABI, latest execution" (same gap as TypeScript #78 and Solidity #79, different blocker).

The on-chain side is deployed and e2e-proven: prefixing calldata with [MAGIC 0xa2264d53][u128 versionKey] executes exactly that version.

The blocker is upstream, and it's small

cdm::import! delegates all call-stub generation to pvm_contract_sdk::abi_import! (cargo-pvm-contract). Every generated .call(self) funnels into one function, CallBuilder::call_raw_inner in pvm-contract-core/src/call.rs, which is hardcoded to write [4-byte selector][ABI args] and immediately send:

input_buf[..4].copy_from_slice(&self.selector[..]);
self.payload.encode_to(&mut input_buf[4..]);
host.call_evm(flags, &address.0, gas, &value, input_buf, None)

There is no seam for a calldata prefix, and the workarounds are dead ends (verified during #76):

  • a wrapper Host can't be injected — users pass self as the call context, whose host type is fixed by #[contract];
  • an extension-trait .call silently loses method resolution to the inherent .call (worse than not existing: habit-typed calls would route to latest with no error);
  • pre-sliced buffers don't help — call_raw_inner sends the same slice it writes.

Upstream ask (cargo-pvm-contract, ~30 lines, CDM-agnostic): an optional calldata preamble on CallBuilder — e.g. preamble: Option<&'static [u8]> (or fixed [u8; 20]) written before the selector in call_raw_inner/delegate_call_raw_inner, plus buffer-size accounting at abi_import's four 4 + encode_len() allocation sites. Inert when unset; useful to any proxy/envelope scheme, not just CDM.

CDM side, once the hook exists

  • pvm_cdm::reference! already receives the package name at expansion time and cdm-macros already reads the pinned version from cdm.json — bake the packed key (major<<64|minor<<32|patch, constants mirrored in contract-registry-core::versioning) into the generated handle's preamble. User code doesn't change:
cdm::import!("@example/counter");
let counter = counter::Counter::cdm_lookup();
counter.increment().call(self)?;   // executes the pinned version, not latest
  • A "latest" spec in cdm.json ⇒ no preamble (today's behavior, made opt-in).
  • Same change enables the follow-on optimization: bake the stable proxy address at build time (cdm_from_env-style) and drop the per-call getAddress(string) registry round-trip from cdm_lookup() — the address is permanent per name now.
  • Extend test:macro and proxy.e2e.test.ts with a pinned Rust consumer case.

Sequencing

  1. Upstream PR/issue on paritytech/cargo-pvm-contract for the CallBuilder preamble (this issue's second section is paste-ready).
  2. Once merged (deps float on branch = "main", so it flows in automatically): CDM-side wiring in pvm-cdm-macros + tests — no on-chain changes, the wire format has been live since #76.

References

  • #76 (wire format + e2e proof of versioned routing), #78 (TypeScript counterpart), #79 (Solidity counterpart).
  • reference-repos/cargo-pvm-contract: crates/pvm-contract-core/src/call.rs (call_raw_inner), crates/pvm-contract-macros/src/abi_import/mod.rs (buffer allocation sites).

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with reference-repos/cargo-pvm-contract/crates/pvm-contract-core/src/call.rs and crates/pvm-contract-macros/src/abi_import/mod.rs, then review the CDM macro paths that generate handles. Verify the upstream preamble hook accounts for buffer sizing and remains inert when unset; then wire pinned versions in pvm-cdm-macros and extend test:macro and proxy.e2e.test.ts with a pinned Rust consumer case.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust, typescript
Domain
developer-experience, testing-qa, tooling
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.