Skip to content

Attestation freshness check breaks under node/contract version skew, causing a submit_participant_info retry storm #3686

Description

@gilcu3

Background

The post-submit confirmation for submit_participant_info reconstructs the attestation's creation time by subtracting a hard-coded constant from the contract-stored expiry (crates/node/src/indexer/tx_sender.rs, TODO(#1637)):

storage_time    = stored_expiry - DEFAULT_EXPIRATION_DURATION_SECONDS;
attestation_age = |now - storage_time|;
is_fresh        = attestation_age < MAX_ATTESTATION_AGE; // 120s

But stored_expiry is stamped by whoever verifies and stores the attestation — the contract (AcceptedAttestation::dstack, crates/mpc-attestation/src/attestation.rs:71) — using the contract's compiled-in DEFAULT_EXPIRATION_DURATION_SECONDS. The node then subtracts the node's constant. When the two differ, the reconstructed age is off by the difference.

This is live now: contract runs 3.12 (DEFAULT_EXPIRATION_DURATION_SECONDS = 7 days), nodes run 3.13 (changed to 1 day in #3626). Reconstructed age = 7d − 1d = 6 days, far over the 120s MAX_ATTESTATION_AGE, so the check never returns Executed:

tx_sender: node found dstack attestation on chain attestation_age=518390.57s attestation_is_fresh=false
ERROR periodic_attestation_submission: failed to submit attestation cause=attestation submission was not executed backoff_duration=60s

Each submission lands on-chain successfully, but the node treats it as NotExecuted and retries at the 60s backoff ceiling (+10s observe) — a ~70s submit_participant_info loop per node, indefinitely, each tx carrying a ~60 KB quote+collateral payload.

Acceptance Criteria

  • Attestation submission confirmation does not depend on node and contract sharing the same DEFAULT_EXPIRATION_DURATION_SECONDS (confirm via stored-vs-submitted identity, or an explicit creation timestamp, rather than expiry − constant).
  • A node running a different version from the contract does not enter a permanent submit_participant_info resubmission loop.

Related: #1637, #1639 (extract timestamp from the certificate instead of the now ± constant heuristic).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions