Repository navigation
Conversation
dstack v0.6.4 removes the epoch-less allowlist setters (addDevice, removeDevice, addComposeHash) from DstackApp and stores allowlist rows per app epoch without inheritance across advances. - Probe the contract generation via ERC-165 (IAppEpochManagement 0x8c0524c4 vs IAppAuthBasicManagement 0x8fd37527, currentAppEpoch() fallback); cache only the generation, never the epoch number, and rethrow transport errors so a flaky RPC cannot downgrade a verdict. - add_device / remove_device / add_compose_hash accept an optional epoch: omitted writes [current, current+1] on epoch contracts (the legacy permanent-row semantics under the writable-range cap), given writes exactly that epoch, and errors on legacy contracts. - check_device_allowed / check_compose_hash_allowed / get_allowed_devices / check_on_chain_prerequisites read the per-epoch getters on epoch contracts. - Selectors and both ERC-165 ids are pinned by tests. Ref: docs/plans/2026-11-13-dstack-epoch-contract-compat-plan.md
- allow-devices add/remove gain an optional --epoch flag passed through to the SDK; on legacy contracts an explicit epoch fails fast with a clear error instead of an on-chain revert. - allow-devices list shows the current app epoch on epoch-aware contracts and reports the written epoch range after add/remove. - deploy / instances add / cvms replicate / envs update surface the SDK's epochsWritten metadata in debug output; no signature changes. - focused_tests.py runs each CLI test file in its own bun process: 'bun test' shares one module registry across the files it loads, so a whole-module mock.module() leaked into sibling files (pre-existing; surfaced when the hook selected instances/add + allow-devices together).
…reads Review findings on the epoch compatibility layer: - Removals default to [0, current+1]: the contract still authorizes any epoch ≤ current, so removing only [current, current+1] left the value fetchable at historical epochs. - The generation probe cache is keyed by chain id + address, and legacy verdicts expire after 5 minutes so an on-chain proxy upgrade is picked up by long-lived processes (epoch verdicts stay permanent; upgrades only go legacy → epoch). - getAllowedDevices accepts an optional epoch to read the allowlist at a specific app epoch (CLI --wait/--epoch verification needs it).
- allow-devices add/remove --wait now verifies the allowlist at the requested epoch instead of always reading the current one, so '--epoch N --wait' no longer times out on a correct write. - Interactive add/remove candidate lists are re-checked on-chain at the requested epoch when --epoch is set (the backend list reflects the current epoch only). - The --epoch help text documents the default ranges: additions write [current, current+1], removals revoke [0, current+1].
A PublicClient without a configured chain previously fell into one "unknown" bucket, so verdicts leaked across networks (reproduced with two real chain-less clients against different chains). The chain id is now resolved from the configured chain or eth_chainId, and the verdict is not cached at all when neither is available. Also correct the removeDevice docstring to the [0, current+1] revocation default.
…epoch The interactive removal pre-filtered candidates by the backend's current-epoch status, so a device that is removed at the current epoch but still allowed at the requested historical epoch never became a candidate. With --epoch the candidate pool is now every known device, and only the on-chain read at the requested epoch decides. Covered by a new interactive test case.
Contributor
📋 Check Results✨ JS SDK - Code FormattingShow format check results🔍 JS SDK - TypeScript Type CheckShow type check output🧪 JS SDK - Test ResultsShow test output📝 JS SDK - Lint CheckShow lint results🌐 JS SDK - Browser CompatibilityShow browser test results🌐 Browser Compatibility ReportBrowser compatibility tests completed across:
The SDK has been verified to work in modern browser environments. Check run: https://github.com/Phala-Network/phala-cloud/actions/runs/43371320963 |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Make the JS SDK and CLI fully compatible with dstack v0.6.4 epoch contracts (DstackKms/DstackApp) ahead of the on-chain proxy upgrade. Every allowlist read/write works against both contract generations: pre-epoch contracts keep the exact legacy behavior, epoch contracts use the epoch-aware functions.
SDK (
@phala/cloud)resolveAppEpochPlanprobes the contract generation via ERC-165 (IAppEpochManagement=0x8c0524c4, legacyIAppAuthBasicManagement=0x8fd37527), with acurrentAppEpoch()fallback. Verdicts are cached per(chainId, address); the chain id comes from the configured chain oreth_chainId, and chain-less clients that cannot identify their network are never cached. Legacy verdicts expire after 5 minutes (so an on-chain proxy upgrade is picked up by long-lived processes); epoch verdicts are permanent (upgrades only go legacy → epoch); transport errors are never cached.resolveAppEpochWritePlandistinguishes add vs remove. An omittedepochwrites[current, current+1]for additions (rows are not inherited across an epoch advance) and revokes[0, current+1]for removals (the contract still authorizes historical epochs). An explicitepochwrites exactly that epoch and is rejected on legacy contracts.addDevice/removeDevice/addComposeHashroute through the write plan and reportepochsWritten.getAllowedDevicesaccepts an optionalepochto read the allowlist at a specific app epoch.CLI (
phala)allow-devices add/removeexpose--epochon epoch-aware contracts. The flag is threaded through--waitverification (reads the requested epoch instead of the current one) and interactive candidate selection (with--epoch, the on-chain read at that epoch decides — devices the backend's current-epoch view reports as removed stay candidates, so historical rows remain revocable).--epoch/--waitand the interactive remove path end to end against mocks.Test infrastructure
scripts/focused_tests.pynow runs each CLI test file in its own process:bun testshares the module registry across files, which leaked whole-module mocks between files.Notes
advanceAppEpoch: the write plan is captured at plan time (current/next), which is the contract's own add-flow semantics.Test plan
sdks/js: 1191 tests pass (fmt/lint/type-check green)sdks/cli: 700 tests pass (fmt/lint/type-check green)