Repository navigation
Exercise UserService accept by package name - #65
Conversation
accept_credential_offer sent the template id of the UserService created event. That id carries the package the UserService was created with, so the accept pinned that version. A participant that no longer vets the old version rejected the command with INVALID_PRESCRIBED_SYNCHRONIZER_ID. G20Group hit this on mainnet against bitsafe-validator-1, which starts at 0.2.2. The exercise now uses the package-name template id, so the participant resolves it to the highest version every informee host vets. The user_service_template_id parameter goes away.
There was a problem hiding this comment.
🟢 Approval recommended
The focused change matches the intended behavior, documents the API break, and has no identified blocking issues.
No open issues 🎉
What changed in this PR
Updates credential-offer acceptance to use a package-name template ID, avoiding failures caused by pinning the UserService’s original package version.
Changes:
- Removes
user_service_template_idfrom acceptance parameters. - Extracts command construction and adds a regression test.
- Documents the breaking API change and caller migration.
| File | Description |
|---|---|
| crates/token/src/credentials.rs | Uses package-name resolution and tests command construction. |
| CHANGELOG.md | Documents the fix and removed parameter. |
Review effort: Balanced
|
Cargo Deny fails on advisories RUSTSEC-2026-0367 and RUSTSEC-2026-0368 for the |
cargo deny fails on the zip 2.4.2 extraction advisories published on 2026-10-09. The token crate only reads a DAR's manifest in memory, so the bugs never applied, but the CI gate blocks every PR until the crate moves past them. ZipArchive::new and by_name are unchanged in 9.x, so dar_check needs no code change.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
I dismiss my approval so that the nits in my next review come first. I will approve again after the author answers them.
hubagaspar91
left a comment
There was a problem hiding this comment.
Four nits from a security review and a PM review. None of them blocks the fix, and the fix itself looks correct.
The token crate reads one manifest from each DAR, and DARs use deflate. The zip default features also pull in AES, bzip2, lzma, ppmd and zstd, and zstd-sys builds C code in a build script. Each unused crate adds supply-chain risk. An advisory against any of them fails Cargo Deny here and in every repo that uses canton-lib. The CHANGELOG also drops "in memory": dar_check opens the DAR from disk and never extracts it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test compared the template id with USER_SERVICE_TEMPLATE_ID, the same constant that the code uses. A package-id value in the constant brings back the mainnet bug, and the old test still passed. The test now asserts the literal package-name string and the choice argument. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CredentialOffer, UserCredential and UserServiceInfo expose the template id of the created event. The old examples passed this value into a command, and that caused the mainnet accept failure. The doc comment tells callers to use the package-name form. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0.12.0 ships #65, which removes the public field AcceptCredentialOfferParams::user_service_template_id. Semver for 0.x versions treats a breaking change as a minor bump. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
What
token::credentials::accept_credential_offernow exercisesUserService_AcceptFreeCredentialOfferwith the package-name template id,#utility-credential-app-v0:...:UserService. It used to send the template id of the UserService created event.AcceptCredentialOfferParamsloses itsuser_service_template_idfield.A second commit bumps
zipfrom 2.4.2 to 9.0.5 so Cargo Deny passes again; see below.Why
A created event's template id carries the package id the contract was created with. The accept therefore pinned the
utility-credential-app-v0version the UserService was created under, instead of letting the participant resolve the name.G20Group hit this on mainnet. Their UserService was created under 0.1.0. bitsafe-validator-1 hosts the BETH issuer party and vets 0.2.2 and later, so the participant rejected the accept with
INVALID_PRESCRIBED_SYNCHRONIZER_ID: participant bitsafe-validator-1 has not vetted package bbe070b7…. With the package-name form the command resolves to the highest version every informee host vets, 0.4.3 today.The zip bump
RUSTSEC-2026-0367 and RUSTSEC-2026-0368 were published on 2026-10-09 against zip 2.4.2, after the last green run on main, so every PR fails Cargo Deny until the crate moves past them. The
tokencrate only readsMETA-INF/MANIFEST.MFfrom a DAR in memory throughZipArchive::newandby_name, both unchanged in 9.x, so the bump needs no code change.cargo deny check advisoriespasses locally.How tested
accept_exercises_user_service_by_package_namebuilds the exercise and asserts the template id is the package-name constant. It failed before the change and passes after.cargo test -p token --lib: 127 passed, 25 ignored (live-ledger tests), before and after the zip bump.cargo clippy --workspace --all-targetsis clean. The changed file passesrustfmt --check.Breaking change
Callers drop
user_service_template_idfromAcceptCredentialOfferParams. The only known callers are the credentials examples in bitsafe-token-lib; DLC-link/bitsafe-token-lib#6 bumps the dependency and removes the field. This needs a minor release, 0.12.0.