Skip to content

Prevent stale attestation proofs before registrar submission#3672

Open
leopoldjoy wants to merge 7 commits into
mainfrom
registrar-proof-age-gate
Open

Prevent stale attestation proofs before registrar submission#3672
leopoldjoy wants to merge 7 commits into
mainfrom
registrar-proof-age-gate

Conversation

@leopoldjoy

@leopoldjoy leopoldjoy commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds a final registrar-side freshness check after proof generation and immediately before TEEProverRegistry.registerSigner calldata is submitted.
  • Reuses the registrar configured max attestation age from the Boundless prover config.
  • Leaves signer-wide proof recovery blocking limited to actual tx/on-chain rejection paths; local stale or undecodable proof checks fail fast without disabling future recovery for that signer.

Tangible value

This prevents the registrar from knowingly submitting a proof that is already doomed to fail the on-chain MAX_AGE check. It protects against recovered Locked proofs that age out while fulfillment completes, fresh proofs that become stale during proof/receipt/tx retries, and future proof providers returning old or malformed journals.

Tests

  • RISC0_SKIP_BUILD_KERNELS=1 cargo test -p base-proof-tee-registrar
  • RISC0_SKIP_BUILD_KERNELS=1 BASE_SUCCINCT_ELF_STUB=1 just build::affected-ci "origin/main"
  • RISC0_SKIP_BUILD_KERNELS=1 BASE_SUCCINCT_ELF_STUB=1 just check::clippy-affected-ci "origin/main"
  • RISC0_SKIP_BUILD_KERNELS=1 BASE_SUCCINCT_ELF_STUB=1 just test-affected-ci "origin/main"

Note: local macOS runs use RISC0_SKIP_BUILD_KERNELS=1 because this machine lacks the xcrun metal tool required by risc0-sys kernel compilation.

Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
@cb-heimdall

cb-heimdall commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

Comment thread crates/proof/tee/registrar/src/signer_manager.rs
Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
Comment thread crates/proof/tee/registrar/src/driver.rs Outdated
Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
Comment thread crates/proof/tee/registrar/src/signer_manager.rs Outdated
leopoldjoy and others added 2 commits June 21, 2026 01:56
Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
@leopoldjoy leopoldjoy requested a review from jackchuma June 21, 2026 02:57
Comment thread crates/proof/tee/registrar/src/signer_manager.rs Outdated
Comment thread crates/proof/tee/registrar/src/signer_manager.rs Outdated
Comment thread crates/proof/tee/registrar/src/signer_manager.rs Outdated
Co-authored-by: OpenCode <opencode-noreply@coinbase.com>
@leopoldjoy leopoldjoy requested a review from jackchuma June 22, 2026 12:51
Co-authored-by: OpenCode <opencode-noreply@coinbase.com>

# Conflicts:
#	crates/proof/tee/registrar/src/signer_manager.rs
Comment thread crates/proof/tee/registrar/src/signer_manager.rs
Comment thread crates/proof/tee/registrar/src/signer_manager.rs
@github-actions

Copy link
Copy Markdown
Contributor

Review Summary

The PR adds a registrar-side freshness gate that decodes the proof journal and checks attestation age before submitting registerSigner transactions on-chain. The SignerManager constructor is refactored to accept a SignerManagerConfig struct, which is a clean improvement. Error variants, tests, and the overall structure look solid.

Findings

1. Missing block_recovery_for_signer for InvalidProofJournal and StaleAttestationProof (correctness concern)

The PR description states that it "blocks proof recovery for the signer when the final gate rejects stale or undecodable proof output." However, neither error path calls self.proof_provider.block_recovery_for_signer() — the tests explicitly assert blocked_signers is empty for both cases. This means the BoundlessProver's deterministic request-ID recovery mechanism may resurface the same bad proof on subsequent cycles, causing repeated futile attempts. This is most concerning for InvalidProofJournal where the proof is permanently undecodable.

2. Inconsistent u128 → u64 conversion in production vs test code (minor)

ensure_attestation_fresh at signer_manager.rs:389 uses as_millis() as u64 (truncating cast), while the test helper proof_output_with_age at line 697 uses the safer u64::try_from(...).unwrap_or(u64::MAX). These should be consistent — the test helper's pattern is more correct.

@github-actions

Copy link
Copy Markdown
Contributor

✅ base-std fork tests: all 616 passed

base/base is fully in sync with the base-std spec.

Dependency Ref Commit
base-std main 4658f1b7
base-anvil 0092692587d8d064dd2c6923ce26a682c58f3694 00926925

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.

3 participants