Skip to content

fix(dips): recover a missing terms_version_hash from chain before cancel - #691

Open
ayushsingh82 wants to merge 1 commit into
edgeandnode:mainfrom
ayushsingh82:fix/638-recover-terms-version-hash
Open

fix(dips): recover a missing terms_version_hash from chain before cancel#691
ayushsingh82 wants to merge 1 commit into
edgeandnode:mainfrom
ayushsingh82:fix/638-recover-terms-version-hash

Conversation

@ayushsingh82

Copy link
Copy Markdown

Closes #638.

Summary

#638 asked for three protections around protocol-managed cancellation silently no-opping on a stale/wrong terms hash:

  1. Confirm the cancel actually took effect (re-read getAgreementDetails after a mined cancel).
  2. Surface a warning/error instead of staying silent when it didn't.
  3. Recover a lost terms_version_hash for pre-migration rows instead of leaving them permanently uncancelable.

Items 1 and 2 already landed in #643 (CancelNotConfirmed + every call site logging a tracing::warn!/tracing::error! and retaining the agreement for retry) — that PR merged after this issue was filed but never explicitly closed it. Item 3 was still missing: a MissingTermsVersionHash agreement had no path back to being cancelable.

Changes

  • ChainClient::fetch_agreement_version_hash — reads getAgreementDetails(id, VERSION_CURRENT).versionHash, refactored to share the RPC call/decode with the existing agreement_still_active.
  • AgreementRegistry::update_terms_version_hash — new Postgres UPDATE, guarded on terms_version_hash IS NULL so it can only backfill, never clobber a real stored value.
  • cancel_agreement_on_chain now resolves the version hash via a new resolve_version_hash helper: use the local one if present and 32 bytes; otherwise fetch it from chain, use it for this cancel, and best-effort persist it (a persistence failure just logs a warning — the cancel still proceeds with the recovered hash). If the contract has no hash on record either, it still fails with MissingTermsVersionHash as before.
  • Reworded the compute_terms_version_hash doc comment (one of the issue's minor cleanups): in protocol-managed mode dipper signs nothing, so the value is only the cancel identifier the collector stored — not "the hash dipper signs over" — and a mismatch is now caught by cancel confirmation rather than failing silently. (The other minor cleanup, giving test fakes a real state field instead of an "already cancelled" result the contract never produces, turned out to already be fixed — chain_listener.rs's MockChainClient::cancel_via_manager already documents and models the real no-op behavior.)
  • cancel_agreement_on_chain and the ChainClient/AgreementRegistry traits gained one parameter/method respectively, which is why this touches 14 files — mostly one-method additions to 8 existing test mocks.

Test plan

  • 2 new unit tests: recovery succeeds and persists (manager_cancel_recovers_missing_hash_from_chain_and_persists_it), and recovery finds nothing on-chain either (manager_cancel_missing_hash_with_nothing_on_chain_is_still_missing_hash_error)
  • cargo test --workspace 'tests::' -- --skip 'tests::it_' — 421 passed, 0 failed (333 in dipper-service, including the 2 new ones)
  • just check (cargo clippy -- -D warnings --force-warn deprecated --force-warn dead-code) — clean
  • just fmt-check (cargo +nightly fmt --all -- --check) — clean
  • cargo build (full workspace) — clean

edgeandnode#638 asked for three protections around protocol-managed cancellation
silently no-opping on a stale/wrong terms hash. Two of the three
(confirming the cancel took effect via a post-cancel getAgreementDetails
read, and surfacing a warning instead of staying silent) already landed
in edgeandnode#643 after the issue was filed. The third — recovering a lost hash
for pre-migration rows instead of leaving them permanently uncancelable
— was still missing.

cancel_agreement_on_chain now falls back to ChainClient::fetch_agreement_version_hash
(getAgreementDetails(id, VERSION_CURRENT).versionHash) when the local
terms_version_hash is absent, uses the recovered hash for the cancel, and
best-effort persists it via a new AgreementRegistry::update_terms_version_hash
so future cancels don't need to re-fetch. If the contract has no hash on
record either, the call still fails with MissingTermsVersionHash as before.

Also rewords the compute_terms_version_hash doc comment: in
protocol-managed mode dipper signs nothing, so the value is only the
cancel identifier the collector stored, not "the hash dipper signs
over" — and a mismatch is now caught by cancel confirmation rather than
failing silently, per the other edgeandnode#638 cleanup item.

Closes edgeandnode#638
@ayushsingh82

Copy link
Copy Markdown
Author

@MoonBoi9001 opened this against #638 — would appreciate a look when you have a moment.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add defence-in-depth confirmation that protocol-managed cancellations took effect

1 participant