paritytech / paritytech/contract-dependency-manager

cdm deploy: Bulletin publish crashes on 'blocks.get(acc.best).number' (polkadot-api observable-client bug)

Open
#59 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

Summary

cdm deploy crashes during the Bulletin metadata-publish step against the Paseo Bulletin node, with:

[Bulletin publish item 1/1] Metadata publish failed (metadata-0): [Bulletin publish] undefined is not an object (evaluating 'blocks.get(acc.best).number')

The first contract fails and all dependents are skipped (dependency failed).

Repro

cdm deploy -n paseo
AssetHub ✔ wss://paseo-asset-hub-next-rpc.polkadot.io
Bulletin ✔ wss://paseo-bulletin-next-rpc.polkadot.io
Registry   0x7671a84f5e7b1bf704f0ad3f43a185ff3d4b303f

@d3pot/organization      ✖   ← Metadata publish failed
@d3pot/repository        ✖   ← Skipped: dependency failed
@d3pot/pull-request      ✖   ← Skipped: dependency failed

AssetHub connects and the registry read succeeds; only the Bulletin publish path crashes.

Root cause

The error is not in CDM code — it originates in polkadot-api's @polkadot-api/observable-client chainHead block-tracking reducer, in the finalized event handler:

@polkadot-api/observable-client@0.18.7/dist/chainHead/streams/pinned-blocks.js:194

case "finalized": {
  const finalized = event.finalizedBlockHashes.slice(-1)[0];
  ...
  acc.finalized = finalized;
  const { blocks } = acc;
  if (blocks.get(acc.best).number < blocks.get(acc.finalized).number)  // ← acc.best not in map → undefined.number → throws
    acc.best = acc.finalized;

blocks.get(acc.best) returns undefined because on this finalized notification acc.best still points to a block hash that is no longer in the pinned blocks map. The line dereferences .number without a guard — unlike the sibling finalized-height reads in the same file, which use ?.number ?? -1.

Call path: MetadataPublisher.publish() (src/lib/contracts/src/publisher.ts:42) → submitAndWatch() (@parity/product-sdk-tx) → papi chainHead subscription → the reducer above → error propagates and is wrapped as [Bulletin publish] ... at src/lib/contracts/src/publisher.ts:45.

Why AssetHub works but Bulletin doesn't: both connect over raw WebSocket via createDirectChainClient (src/lib/env/src/connection.ts:193, createClient(getWsProvider(...))). The Paseo Bulletin node's chainHead finalized/pruning event sequence leaves acc.best dangling; AssetHub's does not.

Why upgrading doesn't fix it

The latest @polkadot-api/observable-client is 0.18.7 (2026-06-02) and line 194 is still unguarded — no upstream fix exists yet.

(Separately: node_modules is stale — the catalog pins polkadot-api: ^2.1.7 in pnpm-workspace.yaml but 2.1.2/2.1.5 are installed. Worth a pnpm install, but it does not fix this bug.)

Options

  1. pnpm patch @polkadot-api/observable-client — guard line 194 like its siblings: (blocks.get(acc.best)?.number ?? -1) < .... Surgical, no resubmission risk, but a vendored patch to maintain until upstream ships a fix. (recommended immediate fix)
  2. Report upstream to polkadot-api with the Paseo Bulletin repro so the finalized handler gets the same ?. guard the finalized-height reads already use — then the local patch can be dropped.
  3. Retry the publish in publisher.ts via withRetry from @parity/product-sdk-tx (already available). Recovers the transient race, but re-runs submitAndWatch → risks double-storing metadata since the crash is in block-tracking, not submission. Would need a CID existence check before resubmit.

Suggested plan

Apply option 1 now, file option 2 upstream, drop the patch once upstream fixes it.

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 src/lib/contracts/src/publisher.ts:42 and :45, then trace submitAndWatch through @polkadot-api/observable-client and the pinned-blocks.js finalized handler at line 194. Reproduce with cdm deploy -n paseo and inspect the pnpm patch workflow. Done means the Bulletin metadata publish completes without the reducer crash, with an upstream report filed and the local patch removable after a fix.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
backend-api-design, blockchain
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.