@mysten-incubation/devstack 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -3
- package/dashboard-ui/assets/grpc-a4usE3Nk.js +3 -0
- package/dashboard-ui/assets/index-B82Bh84P.css +1 -0
- package/dashboard-ui/assets/index-CRYJ4pru.js +1277 -0
- package/dashboard-ui/index.html +2 -2
- package/dist/api/define-capabilities.d.mts +1 -20
- package/dist/api/define-capabilities.mjs +15 -22
- package/dist/api/define-capabilities.mjs.map +1 -1
- package/dist/api/define-devstack-with.d.mts +7 -1
- package/dist/api/define-devstack-with.mjs.map +1 -1
- package/dist/api/define-devstack.mjs.map +1 -1
- package/dist/api/define-plugin.d.mts +2 -1
- package/dist/api/inference-network.d.mts +31 -17
- package/dist/api/inference-network.mjs +40 -43
- package/dist/api/inference-network.mjs.map +1 -1
- package/dist/api/load-config.mjs +88 -0
- package/dist/api/load-config.mjs.map +1 -0
- package/dist/api/mode-narrowed-factory.d.mts +1 -1
- package/dist/api/mode-narrowed-factory.mjs.map +1 -1
- package/dist/api/run-stack-internal.mjs +202 -0
- package/dist/api/run-stack-internal.mjs.map +1 -0
- package/dist/api/run-stack.d.mts +82 -31
- package/dist/api/run-stack.mjs +22 -141
- package/dist/api/run-stack.mjs.map +1 -1
- package/dist/build-integrations/dapp-kit/index.d.mts +61 -0
- package/dist/build-integrations/dapp-kit/index.mjs +58 -0
- package/dist/build-integrations/dapp-kit/index.mjs.map +1 -0
- package/dist/build-integrations/playwright/config.d.mts +1 -30
- package/dist/build-integrations/playwright/config.mjs +1 -27
- package/dist/build-integrations/playwright/config.mjs.map +1 -1
- package/dist/build-integrations/playwright/errors.d.mts +4 -7
- package/dist/build-integrations/playwright/errors.mjs.map +1 -1
- package/dist/build-integrations/playwright/global-setup.d.mts +42 -71
- package/dist/build-integrations/playwright/global-setup.mjs +142 -218
- package/dist/build-integrations/playwright/global-setup.mjs.map +1 -1
- package/dist/build-integrations/playwright/index.d.mts +2 -2
- package/dist/build-integrations/playwright/index.mjs +2 -2
- package/dist/build-integrations/playwright/stack-context.d.mts +3 -1
- package/dist/build-integrations/playwright/stack-context.mjs +4 -2
- package/dist/build-integrations/playwright/stack-context.mjs.map +1 -1
- package/dist/build-integrations/playwright/wallet-context.mjs +44 -19
- package/dist/build-integrations/playwright/wallet-context.mjs.map +1 -1
- package/dist/build-integrations/runtime/cold-start-url.mjs.map +1 -1
- package/dist/build-integrations/runtime/conventional-routes.mjs.map +1 -1
- package/dist/build-integrations/runtime/dapp-kit-slot.mjs.map +1 -1
- package/dist/build-integrations/runtime/discover.d.mts +6 -4
- package/dist/build-integrations/runtime/discover.mjs +15 -4
- package/dist/build-integrations/runtime/discover.mjs.map +1 -1
- package/dist/build-integrations/runtime/endpoint-registry.mjs.map +1 -1
- package/dist/build-integrations/runtime/errors.mjs.map +1 -1
- package/dist/build-integrations/runtime/read-stack-context.mjs +3 -3
- package/dist/build-integrations/runtime/read-stack-context.mjs.map +1 -1
- package/dist/build-integrations/runtime/resolve-discovery-env.d.mts +23 -7
- package/dist/build-integrations/runtime/resolve-discovery-env.mjs +25 -12
- package/dist/build-integrations/runtime/resolve-discovery-env.mjs.map +1 -1
- package/dist/build-integrations/runtime/stack-context.d.mts +2 -2
- package/dist/build-integrations/vite/index.d.mts +84 -19
- package/dist/build-integrations/vite/index.mjs +203 -28
- package/dist/build-integrations/vite/index.mjs.map +1 -1
- package/dist/build-integrations/vitest/config.d.mts +20 -2
- package/dist/build-integrations/vitest/config.mjs +16 -4
- package/dist/build-integrations/vitest/config.mjs.map +1 -1
- package/dist/build-integrations/vitest/env.d.mts +18 -10
- package/dist/build-integrations/vitest/env.mjs +11 -10
- package/dist/build-integrations/vitest/env.mjs.map +1 -1
- package/dist/build-integrations/vitest/errors.d.mts +7 -11
- package/dist/build-integrations/vitest/errors.mjs +3 -4
- package/dist/build-integrations/vitest/errors.mjs.map +1 -1
- package/dist/build-integrations/vitest/global-setup.d.mts +35 -0
- package/dist/build-integrations/vitest/global-setup.mjs +156 -0
- package/dist/build-integrations/vitest/global-setup.mjs.map +1 -0
- package/dist/build-integrations/vitest/index.d.mts +3 -2
- package/dist/build-integrations/vitest/index.mjs +3 -2
- package/dist/build-integrations/vitest/setup.mjs +2 -2
- package/dist/build-integrations/vitest/setup.mjs.map +1 -1
- package/dist/build-integrations/vitest/stack-context.d.mts +5 -3
- package/dist/build-integrations/vitest/stack-context.mjs +3 -2
- package/dist/build-integrations/vitest/stack-context.mjs.map +1 -1
- package/dist/cli/bail.mjs.map +1 -1
- package/dist/cli/doctor-probes.mjs +1 -3
- package/dist/cli/doctor-probes.mjs.map +1 -1
- package/dist/cli/main.d.mts +23 -1
- package/dist/cli/main.mjs +63 -8
- package/dist/cli/main.mjs.map +1 -1
- package/dist/cli/prune-direct.mjs.map +1 -1
- package/dist/cli/snapshot-reader.mjs.map +1 -1
- package/dist/cli/up-lifecycle.mjs.map +1 -1
- package/dist/cli/wirings/apply.mjs +28 -21
- package/dist/cli/wirings/apply.mjs.map +1 -1
- package/dist/cli/wirings/codegen.mjs +108 -0
- package/dist/cli/wirings/codegen.mjs.map +1 -0
- package/dist/cli/wirings/config-loader.mjs +12 -62
- package/dist/cli/wirings/config-loader.mjs.map +1 -1
- package/dist/cli/wirings/dump-ids.mjs +86 -0
- package/dist/cli/wirings/dump-ids.mjs.map +1 -0
- package/dist/cli/wirings/engine-command.mjs +1 -1
- package/dist/cli/wirings/engine-command.mjs.map +1 -1
- package/dist/cli/wirings/identity.mjs +2 -2
- package/dist/cli/wirings/identity.mjs.map +1 -1
- package/dist/cli/wirings/provide-file-system.mjs.map +1 -1
- package/dist/cli/wirings/read-devstack-version.mjs +17 -0
- package/dist/cli/wirings/read-devstack-version.mjs.map +1 -0
- package/dist/cli/wirings/snapshot.mjs +27 -34
- package/dist/cli/wirings/snapshot.mjs.map +1 -1
- package/dist/cli/wirings/up-ipc.mjs +147 -0
- package/dist/cli/wirings/up-ipc.mjs.map +1 -0
- package/dist/cli/wirings/up.mjs +218 -198
- package/dist/cli/wirings/up.mjs.map +1 -1
- package/dist/cli/wirings/wipe.mjs +1 -1
- package/dist/cli/wirings/wipe.mjs.map +1 -1
- package/dist/contracts/chain-probe.d.mts +1 -1
- package/dist/contracts/chain-probe.mjs +1 -1
- package/dist/contracts/chain-probe.mjs.map +1 -1
- package/dist/contracts/codegenable.d.mts +60 -6
- package/dist/contracts/codegenable.mjs +28 -0
- package/dist/contracts/codegenable.mjs.map +1 -0
- package/dist/contracts/config-bindings.mjs +162 -0
- package/dist/contracts/config-bindings.mjs.map +1 -0
- package/dist/contracts/container-runtime.d.mts +23 -17
- package/dist/contracts/plugin-expander.mjs.map +1 -1
- package/dist/contracts/snapshotable.d.mts +5 -7
- package/dist/contracts/wallet-protocol.d.mts +2 -5
- package/dist/contracts/wallet-protocol.mjs +2 -5
- package/dist/contracts/wallet-protocol.mjs.map +1 -1
- package/dist/index.d.mts +21 -26
- package/dist/index.mjs +8 -9
- package/dist/orchestrators/boot.d.mts +28 -0
- package/dist/orchestrators/boot.mjs +440 -0
- package/dist/orchestrators/boot.mjs.map +1 -0
- package/dist/orchestrators/codegen/bindings.d.mts +13 -1
- package/dist/orchestrators/codegen/bindings.mjs +23 -9
- package/dist/orchestrators/codegen/bindings.mjs.map +1 -1
- package/dist/orchestrators/codegen/config-runtime.mjs +208 -0
- package/dist/orchestrators/codegen/config-runtime.mjs.map +1 -0
- package/dist/orchestrators/codegen/emit.mjs +1 -1
- package/dist/orchestrators/codegen/emit.mjs.map +1 -1
- package/dist/orchestrators/codegen/errors.mjs +21 -1
- package/dist/orchestrators/codegen/errors.mjs.map +1 -1
- package/dist/orchestrators/codegen/format.mjs +2 -0
- package/dist/orchestrators/codegen/format.mjs.map +1 -1
- package/dist/orchestrators/codegen/gitignore.mjs +30 -11
- package/dist/orchestrators/codegen/gitignore.mjs.map +1 -1
- package/dist/orchestrators/codegen/id-config.mjs +107 -0
- package/dist/orchestrators/codegen/id-config.mjs.map +1 -0
- package/dist/orchestrators/codegen/output-location.mjs +23 -32
- package/dist/orchestrators/codegen/output-location.mjs.map +1 -1
- package/dist/orchestrators/codegen/paths.mjs +8 -1
- package/dist/orchestrators/codegen/paths.mjs.map +1 -1
- package/dist/orchestrators/codegen/permissions.mjs.map +1 -1
- package/dist/orchestrators/codegen/service.mjs +286 -58
- package/dist/orchestrators/codegen/service.mjs.map +1 -1
- package/dist/orchestrators/layers.mjs +31 -0
- package/dist/orchestrators/layers.mjs.map +1 -0
- package/dist/orchestrators/lifecycle-prune/errors.mjs.map +1 -1
- package/dist/orchestrators/lifecycle-prune/index.mjs +8 -10
- package/dist/orchestrators/lifecycle-prune/index.mjs.map +1 -1
- package/dist/orchestrators/network-options.d.mts +52 -0
- package/dist/orchestrators/network-options.mjs +43 -0
- package/dist/orchestrators/network-options.mjs.map +1 -0
- package/dist/orchestrators/router/cleanup.mjs.map +1 -1
- package/dist/orchestrators/router/cors.mjs.map +1 -1
- package/dist/orchestrators/router/entrypoints.mjs.map +1 -1
- package/dist/orchestrators/router/errors.mjs.map +1 -1
- package/dist/orchestrators/router/file-provider.mjs.map +1 -1
- package/dist/orchestrators/router/hostname.mjs.map +1 -1
- package/dist/orchestrators/router/profile.mjs +1 -1
- package/dist/orchestrators/router/profile.mjs.map +1 -1
- package/dist/orchestrators/router/service.d.mts +2 -2
- package/dist/orchestrators/router/service.mjs +12 -27
- package/dist/orchestrators/router/service.mjs.map +1 -1
- package/dist/orchestrators/router/traefik-container.mjs +1 -1
- package/dist/orchestrators/router/traefik-container.mjs.map +1 -1
- package/dist/orchestrators/snapshot/capture.mjs +171 -195
- package/dist/orchestrators/snapshot/capture.mjs.map +1 -1
- package/dist/orchestrators/snapshot/descriptor.d.mts +1 -1
- package/dist/orchestrators/snapshot/descriptor.mjs +53 -11
- package/dist/orchestrators/snapshot/descriptor.mjs.map +1 -1
- package/dist/orchestrators/snapshot/identity-guard.mjs +3 -5
- package/dist/orchestrators/snapshot/identity-guard.mjs.map +1 -1
- package/dist/orchestrators/snapshot/image-bundle-tags.mjs +32 -101
- package/dist/orchestrators/snapshot/image-bundle-tags.mjs.map +1 -1
- package/dist/orchestrators/snapshot/index.mjs +1 -4
- package/dist/orchestrators/snapshot/integrity.mjs.map +1 -1
- package/dist/orchestrators/snapshot/interrupted-restore.mjs +116 -0
- package/dist/orchestrators/snapshot/interrupted-restore.mjs.map +1 -0
- package/dist/orchestrators/snapshot/phase-error.mjs.map +1 -1
- package/dist/orchestrators/snapshot/prune.mjs +40 -31
- package/dist/orchestrators/snapshot/prune.mjs.map +1 -1
- package/dist/orchestrators/snapshot/restore.mjs +221 -196
- package/dist/orchestrators/snapshot/restore.mjs.map +1 -1
- package/dist/orchestrators/snapshot/service.mjs +72 -62
- package/dist/orchestrators/snapshot/service.mjs.map +1 -1
- package/dist/orchestrators/snapshot/wipe.mjs +67 -56
- package/dist/orchestrators/snapshot/wipe.mjs.map +1 -1
- package/dist/plugins/account/codegen.mjs +3 -0
- package/dist/plugins/account/codegen.mjs.map +1 -1
- package/dist/plugins/account/errors.d.mts +2 -2
- package/dist/plugins/account/errors.mjs +1 -4
- package/dist/plugins/account/errors.mjs.map +1 -1
- package/dist/plugins/account/funding.mjs +3 -27
- package/dist/plugins/account/funding.mjs.map +1 -1
- package/dist/plugins/account/index.d.mts +3 -8
- package/dist/plugins/account/index.mjs +71 -35
- package/dist/plugins/account/index.mjs.map +1 -1
- package/dist/plugins/account/keypair.d.mts +8 -7
- package/dist/plugins/account/keypair.mjs +5 -18
- package/dist/plugins/account/keypair.mjs.map +1 -1
- package/dist/plugins/account/lease.mjs.map +1 -1
- package/dist/plugins/account/registry.d.mts +1 -46
- package/dist/plugins/account/registry.mjs.map +1 -1
- package/dist/plugins/account/service.d.mts +43 -34
- package/dist/plugins/account/service.mjs +9 -54
- package/dist/plugins/account/service.mjs.map +1 -1
- package/dist/plugins/account/snapshot.mjs.map +1 -1
- package/dist/plugins/account/variants/ephemeral.mjs.map +1 -1
- package/dist/plugins/account/variants/impersonate.mjs.map +1 -1
- package/dist/plugins/account/variants/signer.mjs.map +1 -1
- package/dist/plugins/action/discriminator.mjs.map +1 -1
- package/dist/plugins/action/errors.mjs +1 -4
- package/dist/plugins/action/errors.mjs.map +1 -1
- package/dist/plugins/action/execute.mjs +3 -4
- package/dist/plugins/action/execute.mjs.map +1 -1
- package/dist/plugins/action/index.d.mts +2 -2
- package/dist/plugins/action/index.mjs +7 -11
- package/dist/plugins/action/index.mjs.map +1 -1
- package/dist/plugins/action/service.d.mts +5 -7
- package/dist/plugins/action/service.mjs +2 -16
- package/dist/plugins/action/service.mjs.map +1 -1
- package/dist/plugins/coin/address-resolution.mjs.map +1 -1
- package/dist/plugins/coin/codegen.mjs +97 -16
- package/dist/plugins/coin/codegen.mjs.map +1 -1
- package/dist/plugins/coin/discovery.mjs.map +1 -1
- package/dist/plugins/coin/errors.mjs +1 -4
- package/dist/plugins/coin/errors.mjs.map +1 -1
- package/dist/plugins/coin/index.d.mts +4 -34
- package/dist/plugins/coin/index.mjs +47 -28
- package/dist/plugins/coin/index.mjs.map +1 -1
- package/dist/plugins/coin/metadata.d.mts +1 -0
- package/dist/plugins/coin/metadata.mjs +8 -9
- package/dist/plugins/coin/metadata.mjs.map +1 -1
- package/dist/plugins/coin/mint.mjs +7 -21
- package/dist/plugins/coin/mint.mjs.map +1 -1
- package/dist/plugins/coin/registry.mjs +33 -20
- package/dist/plugins/coin/registry.mjs.map +1 -1
- package/dist/plugins/coin/service.d.mts +1 -1
- package/dist/plugins/coin/service.mjs +1 -8
- package/dist/plugins/coin/service.mjs.map +1 -1
- package/dist/plugins/coin/snapshot.mjs.map +1 -1
- package/dist/plugins/coin/type-strings.mjs.map +1 -1
- package/dist/plugins/dashboard/domain.mjs +106 -167
- package/dist/plugins/dashboard/domain.mjs.map +1 -1
- package/dist/plugins/dashboard/index.mjs +13 -13
- package/dist/plugins/dashboard/index.mjs.map +1 -1
- package/dist/plugins/dashboard/origin-policy.mjs +3 -3
- package/dist/plugins/dashboard/origin-policy.mjs.map +1 -1
- package/dist/plugins/dashboard/routable.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/builder.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/enums.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/root.mjs +23 -44
- package/dist/plugins/dashboard/schema/root.mjs.map +1 -1
- package/dist/plugins/dashboard/schema/types.mjs +37 -91
- package/dist/plugins/dashboard/schema/types.mjs.map +1 -1
- package/dist/plugins/dashboard/schema.mjs.map +1 -1
- package/dist/plugins/dashboard/server.mjs.map +1 -1
- package/dist/plugins/deepbook/codegen.d.mts +12 -11
- package/dist/plugins/deepbook/codegen.mjs +108 -11
- package/dist/plugins/deepbook/codegen.mjs.map +1 -1
- package/dist/plugins/deepbook/deploy.mjs +7 -14
- package/dist/plugins/deepbook/deploy.mjs.map +1 -1
- package/dist/plugins/deepbook/errors.mjs +4 -2
- package/dist/plugins/deepbook/errors.mjs.map +1 -1
- package/dist/plugins/deepbook/faucet-strategy.mjs +4 -10
- package/dist/plugins/deepbook/faucet-strategy.mjs.map +1 -1
- package/dist/plugins/deepbook/hash.mjs.map +1 -1
- package/dist/plugins/deepbook/index.d.mts +38 -34
- package/dist/plugins/deepbook/index.mjs +133 -64
- package/dist/plugins/deepbook/index.mjs.map +1 -1
- package/dist/plugins/deepbook/plugin-key.mjs.map +1 -1
- package/dist/plugins/deepbook/pyth/index.mjs +4 -8
- package/dist/plugins/deepbook/pyth/index.mjs.map +1 -1
- package/dist/plugins/deepbook/snapshot.mjs +0 -1
- package/dist/plugins/deepbook/snapshot.mjs.map +1 -1
- package/dist/plugins/deepbook/type-strings.mjs.map +1 -1
- package/dist/plugins/deepbook/types.d.mts +2 -1
- package/dist/plugins/deepbook/types.mjs.map +1 -1
- package/dist/plugins/faucet/dispatcher.d.mts +3 -3
- package/dist/plugins/faucet/dispatcher.mjs.map +1 -1
- package/dist/plugins/faucet/errors.mjs.map +1 -1
- package/dist/plugins/faucet/http.mjs +2 -10
- package/dist/plugins/faucet/http.mjs.map +1 -1
- package/dist/plugins/faucet/index.mjs +0 -1
- package/dist/plugins/faucet/index.mjs.map +1 -1
- package/dist/plugins/host-service/errors.d.mts +1 -3
- package/dist/plugins/host-service/errors.mjs +1 -2
- package/dist/plugins/host-service/errors.mjs.map +1 -1
- package/dist/plugins/host-service/index.d.mts +1 -2
- package/dist/plugins/host-service/index.mjs +11 -11
- package/dist/plugins/host-service/index.mjs.map +1 -1
- package/dist/plugins/host-service/routable.mjs.map +1 -1
- package/dist/plugins/host-service/service.mjs +13 -13
- package/dist/plugins/host-service/service.mjs.map +1 -1
- package/dist/plugins/internal/acquire-on-chain-artifact.mjs.map +1 -1
- package/dist/plugins/internal/codegen-helpers.mjs +2 -0
- package/dist/plugins/internal/codegen-helpers.mjs.map +1 -1
- package/dist/plugins/internal/funding-failure-error.mjs.map +1 -1
- package/dist/plugins/{postgres → internal/postgres-sidecar}/connection.mjs +1 -1
- package/dist/plugins/internal/postgres-sidecar/connection.mjs.map +1 -0
- package/dist/plugins/{postgres → internal/postgres-sidecar}/db-ensure.mjs +30 -16
- package/dist/plugins/internal/postgres-sidecar/db-ensure.mjs.map +1 -0
- package/dist/plugins/internal/postgres-sidecar/errors.mjs +21 -0
- package/dist/plugins/internal/postgres-sidecar/errors.mjs.map +1 -0
- package/dist/{substrate/runtime/scoped-multimap → plugins/internal/postgres-sidecar}/index.mjs +1 -0
- package/dist/plugins/internal/postgres-sidecar/service.mjs +121 -0
- package/dist/plugins/internal/postgres-sidecar/service.mjs.map +1 -0
- package/dist/plugins/package/build.mjs +2 -2
- package/dist/plugins/package/build.mjs.map +1 -1
- package/dist/plugins/package/codegen.d.mts +7 -14
- package/dist/plugins/package/codegen.mjs +187 -59
- package/dist/plugins/package/codegen.mjs.map +1 -1
- package/dist/plugins/package/dep-resolution.mjs +51 -3
- package/dist/plugins/package/dep-resolution.mjs.map +1 -1
- package/dist/plugins/package/errors.mjs +1 -4
- package/dist/plugins/package/errors.mjs.map +1 -1
- package/dist/plugins/package/git-source.d.mts +18 -0
- package/dist/plugins/package/git-source.mjs +119 -0
- package/dist/plugins/package/git-source.mjs.map +1 -0
- package/dist/plugins/package/index.d.mts +28 -19
- package/dist/plugins/package/index.mjs +107 -32
- package/dist/plugins/package/index.mjs.map +1 -1
- package/dist/plugins/package/mode-known.mjs +2 -2
- package/dist/plugins/package/mode-known.mjs.map +1 -1
- package/dist/plugins/package/mode-local.mjs +18 -35
- package/dist/plugins/package/mode-local.mjs.map +1 -1
- package/dist/plugins/package/publish-executor.mjs +13 -8
- package/dist/plugins/package/publish-executor.mjs.map +1 -1
- package/dist/plugins/package/publish-output.d.mts +1 -11
- package/dist/plugins/package/publish-output.mjs +1 -9
- package/dist/plugins/package/publish-output.mjs.map +1 -1
- package/dist/plugins/package/registry.d.mts +1 -1
- package/dist/plugins/package/registry.mjs +26 -14
- package/dist/plugins/package/registry.mjs.map +1 -1
- package/dist/plugins/package/service.mjs.map +1 -1
- package/dist/plugins/package/snapshot.mjs.map +1 -1
- package/dist/plugins/router-entrypoints.mjs +1 -3
- package/dist/plugins/router-entrypoints.mjs.map +1 -1
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs +1 -2
- package/dist/plugins/seal/bootstrap-assets/cargo-image.mjs.map +1 -1
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs +1 -6
- package/dist/plugins/seal/bootstrap-assets/source-fetch.mjs.map +1 -1
- package/dist/plugins/seal/codegen.d.mts +1 -5
- package/dist/plugins/seal/codegen.mjs +83 -12
- package/dist/plugins/seal/codegen.mjs.map +1 -1
- package/dist/plugins/seal/config-render.mjs +2 -6
- package/dist/plugins/seal/config-render.mjs.map +1 -1
- package/dist/plugins/seal/deploy.mjs +18 -29
- package/dist/plugins/seal/deploy.mjs.map +1 -1
- package/dist/plugins/seal/errors.d.mts +4 -5
- package/dist/plugins/seal/errors.mjs +1 -8
- package/dist/plugins/seal/errors.mjs.map +1 -1
- package/dist/plugins/seal/index.d.mts +7 -28
- package/dist/plugins/seal/index.mjs +69 -47
- package/dist/plugins/seal/index.mjs.map +1 -1
- package/dist/plugins/seal/key-manager.mjs.map +1 -1
- package/dist/plugins/seal/key-server.mjs +1 -6
- package/dist/plugins/seal/key-server.mjs.map +1 -1
- package/dist/plugins/seal/keygen.mjs +2 -3
- package/dist/plugins/seal/keygen.mjs.map +1 -1
- package/dist/plugins/seal/mode/fork-known.mjs.map +1 -1
- package/dist/plugins/seal/mode/live.mjs +1 -1
- package/dist/plugins/seal/mode/live.mjs.map +1 -1
- package/dist/plugins/seal/mode/local-keygen.mjs +4 -10
- package/dist/plugins/seal/mode/local-keygen.mjs.map +1 -1
- package/dist/plugins/seal/plugin-key.mjs.map +1 -1
- package/dist/plugins/seal/registry-publish.mjs.map +1 -1
- package/dist/plugins/seal/routable.mjs.map +1 -1
- package/dist/plugins/seal/service.mjs.map +1 -1
- package/dist/plugins/seal/snapshot.mjs +1 -2
- package/dist/plugins/seal/snapshot.mjs.map +1 -1
- package/dist/plugins/sui/auto-tick.mjs +5 -5
- package/dist/plugins/sui/auto-tick.mjs.map +1 -1
- package/dist/plugins/sui/chain-build-container.mjs +2 -2
- package/dist/plugins/sui/chain-build-container.mjs.map +1 -1
- package/dist/plugins/sui/chain-probe.mjs +4 -4
- package/dist/plugins/sui/chain-probe.mjs.map +1 -1
- package/dist/plugins/sui/codegen.d.mts +9 -7
- package/dist/plugins/sui/codegen.mjs +49 -46
- package/dist/plugins/sui/codegen.mjs.map +1 -1
- package/dist/plugins/sui/errors.d.mts +1 -1
- package/dist/plugins/sui/errors.mjs +1 -9
- package/dist/plugins/sui/errors.mjs.map +1 -1
- package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.d.mts +1 -1
- package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/index.mjs +3 -7
- package/dist/plugins/sui/exec/index.mjs.map +1 -0
- package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.mjs +1 -1
- package/dist/plugins/sui/exec/sign-and-dispatch.mjs.map +1 -0
- package/dist/plugins/sui/fork-faucet-strategy.mjs +2 -6
- package/dist/plugins/sui/fork-faucet-strategy.mjs.map +1 -1
- package/dist/plugins/sui/fork-orchestration.mjs +13 -23
- package/dist/plugins/sui/fork-orchestration.mjs.map +1 -1
- package/dist/plugins/sui/fork-transaction.mjs.map +1 -1
- package/dist/plugins/sui/index.d.mts +34 -83
- package/dist/plugins/sui/index.mjs +200 -68
- package/dist/plugins/sui/index.mjs.map +1 -1
- package/dist/{substrate/runtime/sui-ledger → plugins/sui/ledger}/object-ref.mjs +1 -1
- package/dist/plugins/sui/ledger/object-ref.mjs.map +1 -0
- package/dist/plugins/sui/local-faucet-strategy.mjs +1 -5
- package/dist/plugins/sui/local-faucet-strategy.mjs.map +1 -1
- package/dist/plugins/sui/log-attrs.mjs +11 -0
- package/dist/plugins/sui/log-attrs.mjs.map +1 -0
- package/dist/plugins/sui/mode/external.mjs +4 -12
- package/dist/plugins/sui/mode/external.mjs.map +1 -1
- package/dist/plugins/sui/mode/fork.mjs +19 -16
- package/dist/plugins/sui/mode/fork.mjs.map +1 -1
- package/dist/plugins/sui/mode/live.mjs +4 -17
- package/dist/plugins/sui/mode/live.mjs.map +1 -1
- package/dist/plugins/sui/mode/local.d.mts +1 -0
- package/dist/plugins/sui/mode/local.mjs +203 -61
- package/dist/plugins/sui/mode/local.mjs.map +1 -1
- package/dist/plugins/sui/mode/shared-boot.mjs +18 -23
- package/dist/plugins/sui/mode/shared-boot.mjs.map +1 -1
- package/dist/plugins/sui/mode/shared.d.mts +6 -7
- package/dist/plugins/sui/mode/shared.mjs.map +1 -1
- package/dist/plugins/sui/mode/spec.d.mts +23 -6
- package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.mjs +28 -30
- package/dist/plugins/sui/move/index.mjs.map +1 -0
- package/dist/plugins/sui/move-summary-runner.mjs +8 -4
- package/dist/plugins/sui/move-summary-runner.mjs.map +1 -1
- package/dist/{substrate/network.d.mts → plugins/sui/network-config.d.mts} +11 -10
- package/dist/plugins/sui/network-resolver.d.mts +6 -6
- package/dist/plugins/sui/routable.mjs.map +1 -1
- package/dist/plugins/sui/service.mjs +10 -6
- package/dist/plugins/sui/service.mjs.map +1 -1
- package/dist/plugins/sui/snapshot.mjs +10 -5
- package/dist/plugins/sui/snapshot.mjs.map +1 -1
- package/dist/plugins/wallet/codegen.d.mts +8 -6
- package/dist/plugins/wallet/codegen.mjs +4 -10
- package/dist/plugins/wallet/codegen.mjs.map +1 -1
- package/dist/plugins/wallet/errors.mjs +1 -4
- package/dist/plugins/wallet/errors.mjs.map +1 -1
- package/dist/plugins/wallet/index.d.mts +3 -6
- package/dist/plugins/wallet/index.mjs +16 -21
- package/dist/plugins/wallet/index.mjs.map +1 -1
- package/dist/plugins/wallet/origin-policy.mjs +3 -3
- package/dist/plugins/wallet/origin-policy.mjs.map +1 -1
- package/dist/plugins/wallet/pairing.mjs +6 -24
- package/dist/plugins/wallet/pairing.mjs.map +1 -1
- package/dist/plugins/wallet/protocol.mjs.map +1 -1
- package/dist/plugins/wallet/routable.mjs.map +1 -1
- package/dist/plugins/wallet/server.mjs +17 -24
- package/dist/plugins/wallet/server.mjs.map +1 -1
- package/dist/plugins/wallet/service.d.mts +2 -2
- package/dist/plugins/wallet/service.mjs +4 -15
- package/dist/plugins/wallet/service.mjs.map +1 -1
- package/dist/plugins/wallet/snapshot.mjs.map +1 -1
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs +1 -5
- package/dist/plugins/walrus/bootstrap-assets/cargo-image.mjs.map +1 -1
- package/dist/plugins/walrus/codegen.d.mts +2 -13
- package/dist/plugins/walrus/codegen.mjs +93 -28
- package/dist/plugins/walrus/codegen.mjs.map +1 -1
- package/dist/plugins/walrus/deploy-paths.mjs +2 -3
- package/dist/plugins/walrus/deploy-paths.mjs.map +1 -1
- package/dist/plugins/walrus/deploy.mjs +26 -19
- package/dist/plugins/walrus/deploy.mjs.map +1 -1
- package/dist/plugins/walrus/errors.mjs +1 -8
- package/dist/plugins/walrus/errors.mjs.map +1 -1
- package/dist/plugins/walrus/faucet-strategy.mjs +15 -1
- package/dist/plugins/walrus/faucet-strategy.mjs.map +1 -1
- package/dist/plugins/walrus/index.d.mts +13 -44
- package/dist/plugins/walrus/index.mjs +119 -122
- package/dist/plugins/walrus/index.mjs.map +1 -1
- package/dist/plugins/walrus/mode/known-deploy.mjs +6 -6
- package/dist/plugins/walrus/mode/known-deploy.mjs.map +1 -1
- package/dist/plugins/walrus/mode/local-cluster.d.mts +2 -2
- package/dist/plugins/walrus/mode/local-cluster.mjs +2 -10
- package/dist/plugins/walrus/mode/local-cluster.mjs.map +1 -1
- package/dist/plugins/walrus/plugin-key.mjs.map +1 -1
- package/dist/plugins/walrus/registry-publish.mjs.map +1 -1
- package/dist/plugins/walrus/routable.mjs.map +1 -1
- package/dist/plugins/walrus/service.mjs.map +1 -1
- package/dist/plugins/walrus/snapshot.mjs +3 -3
- package/dist/plugins/walrus/snapshot.mjs.map +1 -1
- package/dist/plugins/walrus/storage-nodes.mjs +53 -14
- package/dist/plugins/walrus/storage-nodes.mjs.map +1 -1
- package/dist/plugins/walrus/wal-swap.mjs +4 -8
- package/dist/plugins/walrus/wal-swap.mjs.map +1 -1
- package/dist/primitives/artifact-publisher.mjs.map +1 -1
- package/dist/primitives/cache.d.mts +1 -1
- package/dist/runtime/docker/client.mjs +47 -3
- package/dist/runtime/docker/client.mjs.map +1 -1
- package/dist/runtime/docker/container.mjs +37 -57
- package/dist/runtime/docker/container.mjs.map +1 -1
- package/dist/runtime/docker/errors.mjs.map +1 -1
- package/dist/runtime/docker/exec.mjs +2 -2
- package/dist/runtime/docker/exec.mjs.map +1 -1
- package/dist/runtime/docker/image.mjs +10 -11
- package/dist/runtime/docker/image.mjs.map +1 -1
- package/dist/runtime/docker/index.mjs +0 -1
- package/dist/runtime/docker/inspect-and-decode.mjs.map +1 -1
- package/dist/runtime/docker/inventory.mjs +9 -9
- package/dist/runtime/docker/inventory.mjs.map +1 -1
- package/dist/runtime/docker/labels.mjs +12 -1
- package/dist/runtime/docker/labels.mjs.map +1 -1
- package/dist/runtime/docker/network.mjs +6 -6
- package/dist/runtime/docker/network.mjs.map +1 -1
- package/dist/runtime/docker/render-run-args.mjs.map +1 -1
- package/dist/runtime/docker/service.mjs +31 -45
- package/dist/runtime/docker/service.mjs.map +1 -1
- package/dist/runtime/docker/sweep.mjs +14 -64
- package/dist/runtime/docker/sweep.mjs.map +1 -1
- package/dist/runtime/docker/volume.mjs +1 -1
- package/dist/runtime/docker/volume.mjs.map +1 -1
- package/dist/runtime/docker/wrap.mjs +14 -2
- package/dist/runtime/docker/wrap.mjs.map +1 -1
- package/dist/substrate/brand.d.mts +2 -5
- package/dist/substrate/brand.mjs +3 -2
- package/dist/substrate/brand.mjs.map +1 -1
- package/dist/substrate/cross-process.mjs +2 -16
- package/dist/substrate/cross-process.mjs.map +1 -1
- package/dist/substrate/event-time.mjs +0 -2
- package/dist/substrate/event-time.mjs.map +1 -1
- package/dist/substrate/events.d.mts +46 -16
- package/dist/substrate/identity.d.mts +11 -5
- package/dist/substrate/manifest.d.mts +33 -26
- package/dist/substrate/manifest.mjs +8 -3
- package/dist/substrate/manifest.mjs.map +1 -1
- package/dist/substrate/options.d.mts +33 -4
- package/dist/substrate/plugin-ctx.d.mts +70 -0
- package/dist/substrate/plugin-ctx.mjs +66 -0
- package/dist/substrate/plugin-ctx.mjs.map +1 -0
- package/dist/substrate/plugin.d.mts +46 -38
- package/dist/substrate/plugin.mjs +13 -9
- package/dist/substrate/plugin.mjs.map +1 -1
- package/dist/substrate/projection.d.mts +1 -1
- package/dist/substrate/runtime/atomic-write.mjs +3 -4
- package/dist/substrate/runtime/atomic-write.mjs.map +1 -1
- package/dist/substrate/runtime/cache/schema.mjs.map +1 -1
- package/dist/substrate/runtime/cache/service.mjs +50 -20
- package/dist/substrate/runtime/cache/service.mjs.map +1 -1
- package/dist/substrate/runtime/config-validation.mjs.map +1 -1
- package/dist/substrate/runtime/control-plane/domain.mjs +34 -12
- package/dist/substrate/runtime/control-plane/domain.mjs.map +1 -1
- package/dist/substrate/runtime/control-plane/service.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs +14 -17
- package/dist/substrate/runtime/cross-process/command-channel/channel.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/file-channel.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/protocol.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/command-channel/runtime-control-lock.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/index.mjs +0 -2
- package/dist/substrate/runtime/cross-process/live-clock.mjs +1 -1
- package/dist/substrate/runtime/cross-process/live-clock.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/liveness.mjs +11 -18
- package/dist/substrate/runtime/cross-process/liveness.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs +2 -2
- package/dist/substrate/runtime/cross-process/reclaim-stale-file.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/roster.mjs +17 -127
- package/dist/substrate/runtime/cross-process/roster.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/self-pid.mjs.map +1 -1
- package/dist/substrate/runtime/cross-process/stack-lock.mjs +29 -28
- package/dist/substrate/runtime/cross-process/stack-lock.mjs.map +1 -1
- package/dist/substrate/runtime/current-plugin.mjs.map +1 -1
- package/dist/substrate/runtime/errors.mjs +1 -13
- package/dist/substrate/runtime/errors.mjs.map +1 -1
- package/dist/substrate/runtime/format-unknown-error.mjs.map +1 -1
- package/dist/substrate/runtime/host-bind-mount-owner.mjs.map +1 -1
- package/dist/substrate/runtime/host-gateway.mjs.map +1 -1
- package/dist/substrate/runtime/host-tree-tar/index.mjs +15 -163
- package/dist/substrate/runtime/host-tree-tar/index.mjs.map +1 -1
- package/dist/substrate/runtime/http-probe.d.mts +1 -3
- package/dist/substrate/runtime/http-probe.mjs.map +1 -1
- package/dist/substrate/runtime/index.mjs +1 -6
- package/dist/substrate/runtime/lease-broker/service.mjs +5 -23
- package/dist/substrate/runtime/lease-broker/service.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs +3 -3
- package/dist/substrate/runtime/lifecycle/dep-graph.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/graph-input-id.d.mts +1 -0
- package/dist/substrate/runtime/lifecycle/graph-input-id.mjs +133 -0
- package/dist/substrate/runtime/lifecycle/graph-input-id.mjs.map +1 -0
- package/dist/substrate/runtime/lifecycle/index.mjs +2 -2
- package/dist/substrate/runtime/lifecycle/plugin-registry.d.mts +1 -1
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs +22 -1
- package/dist/substrate/runtime/lifecycle/plugin-registry.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/ready-gate.mjs +2 -15
- package/dist/substrate/runtime/lifecycle/ready-gate.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/selective-restart.mjs +29 -25
- package/dist/substrate/runtime/lifecycle/selective-restart.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/signals.mjs +1 -1
- package/dist/substrate/runtime/lifecycle/signals.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/state-machine.mjs.map +1 -1
- package/dist/substrate/runtime/lifecycle/watch-attribution.d.mts +1 -1
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs +0 -1
- package/dist/substrate/runtime/lifecycle/watch-attribution.mjs.map +1 -1
- package/dist/substrate/runtime/managed-container.d.mts +5 -1
- package/dist/substrate/runtime/managed-container.mjs +8 -10
- package/dist/substrate/runtime/managed-container.mjs.map +1 -1
- package/dist/substrate/runtime/manifest/manifest.mjs +8 -30
- package/dist/substrate/runtime/manifest/manifest.mjs.map +1 -1
- package/dist/substrate/runtime/mode-errors.d.mts +1 -2
- package/dist/substrate/runtime/mode-errors.mjs.map +1 -1
- package/dist/substrate/runtime/observability/cascade-formatter.mjs +1 -11
- package/dist/substrate/runtime/observability/cascade-formatter.mjs.map +1 -1
- package/dist/substrate/runtime/observability/ignore-with-log.mjs.map +1 -1
- package/dist/substrate/runtime/observability/index.d.mts +1 -1
- package/dist/substrate/runtime/observability/index.mjs +4 -6
- package/dist/substrate/runtime/observability/log-attrs.mjs +46 -0
- package/dist/substrate/runtime/observability/log-attrs.mjs.map +1 -0
- package/dist/substrate/runtime/observability/log-store.mjs.map +1 -1
- package/dist/substrate/runtime/observability/logger.mjs +3 -3
- package/dist/substrate/runtime/observability/logger.mjs.map +1 -1
- package/dist/substrate/runtime/observability/output-truncate.mjs.map +1 -1
- package/dist/substrate/runtime/observability/pretty-error.mjs.map +1 -1
- package/dist/substrate/runtime/observability/process-lines.mjs.map +1 -1
- package/dist/substrate/runtime/observability/redaction.mjs.map +1 -1
- package/dist/substrate/runtime/observability/subprocess-capture.mjs +2 -2
- package/dist/substrate/runtime/observability/subprocess-capture.mjs.map +1 -1
- package/dist/substrate/runtime/passthrough-or-wrap.mjs.map +1 -1
- package/dist/substrate/runtime/paths.mjs +27 -9
- package/dist/substrate/runtime/paths.mjs.map +1 -1
- package/dist/substrate/runtime/phase-preserving-produce.mjs.map +1 -1
- package/dist/substrate/runtime/port-broker/service.mjs +10 -27
- package/dist/substrate/runtime/port-broker/service.mjs.map +1 -1
- package/dist/substrate/runtime/post-acquire-tasks.mjs.map +1 -1
- package/dist/substrate/runtime/probes.d.mts +2 -3
- package/dist/substrate/runtime/probes.mjs.map +1 -1
- package/dist/substrate/runtime/process-supervisor.mjs.map +1 -1
- package/dist/substrate/runtime/projection/operational-endpoints.mjs.map +1 -1
- package/dist/substrate/runtime/projection/state-ref.mjs.map +1 -1
- package/dist/substrate/runtime/projection/update.mjs +87 -11
- package/dist/substrate/runtime/projection/update.mjs.map +1 -1
- package/dist/substrate/runtime/random-suffix.mjs.map +1 -1
- package/dist/substrate/runtime/reconcile/fs-plan.mjs +146 -0
- package/dist/substrate/runtime/reconcile/fs-plan.mjs.map +1 -0
- package/dist/substrate/runtime/reconcile/graph.mjs +19 -0
- package/dist/substrate/runtime/reconcile/graph.mjs.map +1 -0
- package/dist/substrate/runtime/reconcile/index.mjs +5 -0
- package/dist/substrate/runtime/reconcile/label.mjs +41 -0
- package/dist/substrate/runtime/reconcile/label.mjs.map +1 -0
- package/dist/substrate/runtime/reconcile/spec.mjs +15 -0
- package/dist/substrate/runtime/reconcile/spec.mjs.map +1 -0
- package/dist/substrate/runtime/retry-policy.d.mts +2 -3
- package/dist/substrate/runtime/retry-policy.mjs.map +1 -1
- package/dist/substrate/runtime/routed-url.mjs.map +1 -1
- package/dist/substrate/runtime/runtime-decode.mjs.map +1 -1
- package/dist/substrate/runtime/scoped-http-server.mjs.map +1 -1
- package/dist/substrate/runtime/stage-and-swap/index.mjs +49 -12
- package/dist/substrate/runtime/stage-and-swap/index.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/chain-keyed-strategy-for.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/chain-probe-for.mjs.map +1 -1
- package/dist/substrate/runtime/strategy-registry/service.mjs +29 -17
- package/dist/substrate/runtime/strategy-registry/service.mjs.map +1 -1
- package/dist/substrate/runtime/subnet-broker.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/acquire-node.mjs +188 -56
- package/dist/substrate/runtime/supervisor/acquire-node.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/background-tasks.mjs +79 -65
- package/dist/substrate/runtime/supervisor/background-tasks.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/command-loop.mjs +82 -23
- package/dist/substrate/runtime/supervisor/command-loop.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs +16 -0
- package/dist/substrate/runtime/supervisor/contribution-dispatcher.mjs.map +1 -0
- package/dist/substrate/runtime/supervisor/errors.mjs +11 -2
- package/dist/substrate/runtime/supervisor/errors.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/index.mjs +2 -0
- package/dist/substrate/runtime/supervisor/shutdown.mjs +6 -6
- package/dist/substrate/runtime/supervisor/shutdown.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs +60 -70
- package/dist/substrate/runtime/supervisor/start-supervisor.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/state.d.mts +1 -1
- package/dist/substrate/runtime/supervisor/state.mjs +1 -1
- package/dist/substrate/runtime/supervisor/state.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/teardown.mjs +10 -9
- package/dist/substrate/runtime/supervisor/teardown.mjs.map +1 -1
- package/dist/substrate/runtime/supervisor/wiring.mjs +6 -20
- package/dist/substrate/runtime/supervisor/wiring.mjs.map +1 -1
- package/dist/substrate/runtime/tar/reader.mjs +216 -0
- package/dist/substrate/runtime/tar/reader.mjs.map +1 -0
- package/dist/substrate/runtime/typed-env.mjs.map +1 -1
- package/dist/substrate/versioned-doc-schema.mjs.map +1 -1
- package/dist/substrate/versioned-doc-sync.mjs +5 -5
- package/dist/substrate/versioned-doc-sync.mjs.map +1 -1
- package/dist/surfaces/cli/command-tree.mjs +49 -7
- package/dist/surfaces/cli/command-tree.mjs.map +1 -1
- package/dist/surfaces/cli/commands/config.mjs +1 -1
- package/dist/surfaces/cli/commands/config.mjs.map +1 -1
- package/dist/surfaces/cli/commands/confirm-node.mjs.map +1 -1
- package/dist/surfaces/cli/commands/confirm.mjs.map +1 -1
- package/dist/surfaces/cli/commands/doctor.mjs +1 -1
- package/dist/surfaces/cli/commands/doctor.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune-picker-entry.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune-picker.mjs.map +1 -1
- package/dist/surfaces/cli/commands/prune.mjs +1 -1
- package/dist/surfaces/cli/commands/prune.mjs.map +1 -1
- package/dist/surfaces/cli/commands/snapshot.mjs +1 -1
- package/dist/surfaces/cli/commands/snapshot.mjs.map +1 -1
- package/dist/surfaces/cli/commands/status.mjs +1 -1
- package/dist/surfaces/cli/commands/status.mjs.map +1 -1
- package/dist/surfaces/cli/commands/supervisor-presence.mjs.map +1 -1
- package/dist/surfaces/cli/commands/wipe.mjs +3 -4
- package/dist/surfaces/cli/commands/wipe.mjs.map +1 -1
- package/dist/surfaces/cli/envelope.mjs.map +1 -1
- package/dist/surfaces/cli/errors.mjs.map +1 -1
- package/dist/surfaces/cli/flags.mjs.map +1 -1
- package/dist/surfaces/cli/index.mjs +45 -14
- package/dist/surfaces/cli/index.mjs.map +1 -1
- package/dist/surfaces/cli/output.mjs.map +1 -1
- package/dist/surfaces/cli/sysexits.mjs.map +1 -1
- package/dist/surfaces/tui/app.mjs +0 -21
- package/dist/surfaces/tui/app.mjs.map +1 -1
- package/dist/surfaces/tui/dashboard.mjs +0 -48
- package/dist/surfaces/tui/dashboard.mjs.map +1 -1
- package/dist/surfaces/tui/display-derivation.mjs +80 -16
- package/dist/surfaces/tui/display-derivation.mjs.map +1 -1
- package/dist/surfaces/tui/errors.mjs.map +1 -1
- package/dist/surfaces/tui/event-log.mjs +0 -9
- package/dist/surfaces/tui/event-log.mjs.map +1 -1
- package/dist/surfaces/tui/heartbeat.mjs.map +1 -1
- package/dist/surfaces/tui/index.mjs +2 -2
- package/dist/surfaces/tui/index.mjs.map +1 -1
- package/dist/surfaces/tui/input.mjs.map +1 -1
- package/dist/surfaces/tui/mode-detect.mjs.map +1 -1
- package/dist/surfaces/tui/mount-ink.mjs.map +1 -1
- package/dist/surfaces/tui/plain-renderer.mjs +26 -19
- package/dist/surfaces/tui/plain-renderer.mjs.map +1 -1
- package/dist/surfaces/tui/resource-table.mjs +8 -10
- package/dist/surfaces/tui/resource-table.mjs.map +1 -1
- package/images/postgres/Dockerfile +0 -1
- package/images/sui/Dockerfile +27 -54
- package/images/sui/entrypoint.sh +17 -179
- package/package.json +23 -15
- package/dashboard-ui/assets/index-Bmi1UtAg.js +0 -1356
- package/dashboard-ui/assets/index-D5EShVt4.js +0 -3
- package/dashboard-ui/assets/index-Deml9drg.css +0 -1
- package/dist/api/plugin-errors.d.mts +0 -7
- package/dist/api/plugin-errors.mjs +0 -10
- package/dist/api/plugin-errors.mjs.map +0 -1
- package/dist/cli/wirings/build-verb-layers.mjs +0 -42
- package/dist/cli/wirings/build-verb-layers.mjs.map +0 -1
- package/dist/contracts/capability-decl.d.mts +0 -40
- package/dist/orchestrators/built-in-plugin-layers.mjs +0 -54
- package/dist/orchestrators/built-in-plugin-layers.mjs.map +0 -1
- package/dist/orchestrators/run.mjs +0 -91
- package/dist/orchestrators/run.mjs.map +0 -1
- package/dist/orchestrators/runtime-composition.d.mts +0 -10
- package/dist/orchestrators/runtime-composition.mjs +0 -252
- package/dist/orchestrators/runtime-composition.mjs.map +0 -1
- package/dist/orchestrators/snapshot/capture-command.d.mts +0 -1
- package/dist/orchestrators/snapshot/capture-command.mjs +0 -25
- package/dist/orchestrators/snapshot/capture-command.mjs.map +0 -1
- package/dist/orchestrators/snapshot/pending-marker.mjs +0 -99
- package/dist/orchestrators/snapshot/pending-marker.mjs.map +0 -1
- package/dist/orchestrators/snapshot/recover-pending.mjs +0 -223
- package/dist/orchestrators/snapshot/recover-pending.mjs.map +0 -1
- package/dist/orchestrators/snapshot/state-document.d.mts +0 -1
- package/dist/orchestrators/snapshot/state-document.mjs +0 -58
- package/dist/orchestrators/snapshot/state-document.mjs.map +0 -1
- package/dist/plugins/account/spans.mjs +0 -16
- package/dist/plugins/account/spans.mjs.map +0 -1
- package/dist/plugins/account/variants/env.mjs +0 -24
- package/dist/plugins/account/variants/env.mjs.map +0 -1
- package/dist/plugins/account/variants/inline.mjs +0 -13
- package/dist/plugins/account/variants/inline.mjs.map +0 -1
- package/dist/plugins/account/variants/keystore.mjs +0 -91
- package/dist/plugins/account/variants/keystore.mjs.map +0 -1
- package/dist/plugins/action/spans.mjs +0 -11
- package/dist/plugins/action/spans.mjs.map +0 -1
- package/dist/plugins/coin/spans.mjs +0 -20
- package/dist/plugins/coin/spans.mjs.map +0 -1
- package/dist/plugins/deepbook/spans.mjs +0 -18
- package/dist/plugins/deepbook/spans.mjs.map +0 -1
- package/dist/plugins/faucet/spans.mjs +0 -12
- package/dist/plugins/faucet/spans.mjs.map +0 -1
- package/dist/plugins/package/spans.mjs +0 -14
- package/dist/plugins/package/spans.mjs.map +0 -1
- package/dist/plugins/postgres/codegen.mjs +0 -42
- package/dist/plugins/postgres/codegen.mjs.map +0 -1
- package/dist/plugins/postgres/connection.d.mts +0 -33
- package/dist/plugins/postgres/connection.mjs.map +0 -1
- package/dist/plugins/postgres/db-ensure.mjs.map +0 -1
- package/dist/plugins/postgres/errors.d.mts +0 -60
- package/dist/plugins/postgres/errors.mjs +0 -29
- package/dist/plugins/postgres/errors.mjs.map +0 -1
- package/dist/plugins/postgres/index.d.mts +0 -37
- package/dist/plugins/postgres/index.mjs +0 -68
- package/dist/plugins/postgres/index.mjs.map +0 -1
- package/dist/plugins/postgres/routable.mjs +0 -33
- package/dist/plugins/postgres/routable.mjs.map +0 -1
- package/dist/plugins/postgres/service.d.mts +0 -50
- package/dist/plugins/postgres/service.mjs +0 -179
- package/dist/plugins/postgres/service.mjs.map +0 -1
- package/dist/plugins/postgres/snapshot.mjs +0 -32
- package/dist/plugins/postgres/snapshot.mjs.map +0 -1
- package/dist/plugins/postgres/spans.mjs +0 -11
- package/dist/plugins/postgres/spans.mjs.map +0 -1
- package/dist/plugins/seal/spans.mjs +0 -18
- package/dist/plugins/seal/spans.mjs.map +0 -1
- package/dist/plugins/sui/spans.mjs +0 -17
- package/dist/plugins/sui/spans.mjs.map +0 -1
- package/dist/plugins/wallet/spans.mjs +0 -22
- package/dist/plugins/wallet/spans.mjs.map +0 -1
- package/dist/plugins/walrus/registry-publish.d.mts +0 -24
- package/dist/plugins/walrus/spans.mjs +0 -18
- package/dist/plugins/walrus/spans.mjs.map +0 -1
- package/dist/runtime/docker/logs.d.mts +0 -1
- package/dist/runtime/docker/logs.mjs +0 -34
- package/dist/runtime/docker/logs.mjs.map +0 -1
- package/dist/substrate/runtime/artifact-publisher/index.mjs +0 -86
- package/dist/substrate/runtime/artifact-publisher/index.mjs.map +0 -1
- package/dist/substrate/runtime/capability-sinks/index.d.mts +0 -1
- package/dist/substrate/runtime/capability-sinks/index.mjs +0 -3
- package/dist/substrate/runtime/capability-sinks/layer.d.mts +0 -1
- package/dist/substrate/runtime/capability-sinks/layer.mjs +0 -31
- package/dist/substrate/runtime/capability-sinks/layer.mjs.map +0 -1
- package/dist/substrate/runtime/capability-sinks/service.d.mts +0 -95
- package/dist/substrate/runtime/capability-sinks/service.mjs +0 -69
- package/dist/substrate/runtime/capability-sinks/service.mjs.map +0 -1
- package/dist/substrate/runtime/cross-process/lock.d.mts +0 -1
- package/dist/substrate/runtime/cross-process/lock.mjs +0 -23
- package/dist/substrate/runtime/cross-process/lock.mjs.map +0 -1
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs +0 -113
- package/dist/substrate/runtime/cross-process/snapshot-reservation.mjs.map +0 -1
- package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs +0 -31
- package/dist/substrate/runtime/lifecycle/lifecycle-fact.mjs.map +0 -1
- package/dist/substrate/runtime/observability/formatter-registry.d.mts +0 -1
- package/dist/substrate/runtime/observability/formatter-registry.mjs +0 -48
- package/dist/substrate/runtime/observability/formatter-registry.mjs.map +0 -1
- package/dist/substrate/runtime/observability/span-store.d.mts +0 -1
- package/dist/substrate/runtime/observability/span-store.mjs +0 -110
- package/dist/substrate/runtime/observability/span-store.mjs.map +0 -1
- package/dist/substrate/runtime/observability/spans.d.mts +0 -1
- package/dist/substrate/runtime/observability/spans.mjs +0 -87
- package/dist/substrate/runtime/observability/spans.mjs.map +0 -1
- package/dist/substrate/runtime/projection/index.mjs +0 -4
- package/dist/substrate/runtime/projection/persisted.mjs +0 -213
- package/dist/substrate/runtime/projection/persisted.mjs.map +0 -1
- package/dist/substrate/runtime/scoped-multimap/service.mjs +0 -52
- package/dist/substrate/runtime/scoped-multimap/service.mjs.map +0 -1
- package/dist/substrate/runtime/scoped-ref-map/index.mjs +0 -2
- package/dist/substrate/runtime/scoped-ref-map/service.mjs +0 -83
- package/dist/substrate/runtime/scoped-ref-map/service.mjs.map +0 -1
- package/dist/substrate/runtime/state-store/index.mjs +0 -3
- package/dist/substrate/runtime/state-store/schema.d.mts +0 -1
- package/dist/substrate/runtime/state-store/schema.mjs +0 -41
- package/dist/substrate/runtime/state-store/schema.mjs.map +0 -1
- package/dist/substrate/runtime/state-store/service.d.mts +0 -1
- package/dist/substrate/runtime/state-store/service.mjs +0 -145
- package/dist/substrate/runtime/state-store/service.mjs.map +0 -1
- package/dist/substrate/runtime/sui-execute/index.mjs.map +0 -1
- package/dist/substrate/runtime/sui-execute/sign-and-dispatch.mjs.map +0 -1
- package/dist/substrate/runtime/sui-ledger/object-ref.mjs.map +0 -1
- package/dist/substrate/runtime/sui-move-build/index.mjs.map +0 -1
- package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs +0 -151
- package/dist/substrate/runtime/supervisor/dispatch-contributions.mjs.map +0 -1
- package/dist/substrate/state-store.d.mts +0 -1
- /package/dist/orchestrators/{snapshot/pending-marker.d.mts → codegen/id-config.d.mts} +0 -0
- /package/dist/orchestrators/snapshot/{recover-pending.d.mts → interrupted-restore.d.mts} +0 -0
- /package/dist/{substrate/runtime/sui-execute → plugins/sui/exec}/sign-and-dispatch.d.mts +0 -0
- /package/dist/plugins/{postgres/snapshot.d.mts → sui/ledger/object-ref.d.mts} +0 -0
- /package/dist/{substrate/runtime/sui-move-build → plugins/sui/move}/index.d.mts +0 -0
- /package/dist/substrate/runtime/{state-store/index.d.mts → reconcile/graph.d.mts} +0 -0
- /package/dist/substrate/runtime/{cross-process/snapshot-reservation.d.mts → supervisor/contribution-dispatcher.d.mts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"local-cluster.mjs","names":["brandContentHash"],"sources":["../../../../src/plugins/walrus/mode/local-cluster.ts"],"sourcesContent":["// Walrus mode — local cluster.\n//\n// Distilled-doc reference (06-walrus.md §\"Lifecycle: Startup —\n// local cluster\"). Eight ordered phases:\n//\n// 0. Yield deps (Sui, Identity, ChainProbe, faucet strategy opt).\n// 1. Image build — upstream cargo image (bootstrap asset) +\n// wrapper image (inline; content-addressed on\n// the upstream tag + suiVersion).\n// 1b. Docker network create — per-stack `/24` via\n// `Docker.networkCreate(networkName, {subnet})`.\n// 2. Deploy contracts — via `ArtifactPublisher`. The\n// publisher folds chainId into the cache\n// key; verify probes BOTH the on-disk\n// `deploy` file AND on-chain object\n// existence; produce runs the deploy\n// one-shot.\n// 3. Register committee — currently a typed no-op (distilled-doc\n// opportunity #3: drop the cargo-culted\n// placeholder). We omit it entirely in\n// v3 rewrite.\n// 4. Storage nodes — parallel boot of N storage-node containers.\n// 5. Exchange resolution — on-chain getObject + parse type.\n// Degrades to undefined on\n// OBJECT_NOT_FOUND.\n// 6. Proxy URL pick — nodes[0].rpcUrl is the representative\n// aggregator/publisher.\n// 7a. WAL faucet strategy register — opt-in when an exchange exists.\n// 8. Registries — package + endpoint + walrus-state.\n//\n// What this file owns: the dispatch shape + the typed options\n// surface + the synchronous factory-time validation.\n//\n// What this file delegates: container/Move heavy paths live in\n// `storage-nodes.ts`, `deploy.ts`, and the `ArtifactPublisher`\n// primitive.\n\nimport { Effect, FileSystem, Path, type Scope } from 'effect';\n\nimport type {\n\tArtifactPublishError,\n\tArtifactPublisher,\n} from '../../../primitives/artifact-publisher.ts';\nimport type { ChainProbe } from '../../../contracts/chain-probe.ts';\nimport type { ContainerRuntime } from '../../../contracts/container-runtime.ts';\nimport type { SuiProbeKey } from '../../sui/index.ts';\nimport { contentHash as brandContentHash } from '../../../substrate/brand.ts';\nimport type { ChainId } from '../../../substrate/brand.ts';\nimport { expectPositiveInteger } from '../../../substrate/runtime/config-validation.ts';\nimport { setCurrentPluginPhase } from '../../../substrate/runtime/current-plugin.ts';\nimport { SpanAttr } from '../../../substrate/runtime/observability/spans.ts';\nimport { walrusConfigError, walrusPluginError, type WalrusError } from '../errors.ts';\nimport { WALRUS_MAX_NODE_COUNT } from '../routable.ts';\nimport { WalrusSpans } from '../spans.ts';\nimport type { WalrusStorageNode } from '../storage-nodes.ts';\nimport {\n\tDEFAULT_NODE_READY_TIMEOUT_MS,\n\tDEFAULT_CONTAINER_API_PORT,\n\tWALRUS_NODE_IP_BASE,\n\tcomputePublicHostname,\n\tstartStorageNodes,\n} from '../storage-nodes.ts';\nimport { deployWalrusContracts, type CachedDeployState } from '../deploy.ts';\nimport {\n\tDEFAULT_SUI_VERSION,\n\tDEFAULT_WALRUS_REF,\n\tresolveCargoImage,\n} from '../bootstrap-assets/cargo-image.ts';\nimport {\n\tmakeWalFaucetStrategy,\n\twalPackageIdFromCoinType,\n\tresolveWalCoinType,\n\ttype WalFaucetStrategy,\n} from '../faucet-strategy.ts';\nimport { resolveWalExchange, type WalExchangeHandle, type WalSwapSdk } from '../wal-swap.ts';\n\n/** Options for the local-cluster mode. Mirrors v3\n * `WalrusLocalClusterOptions<Name>` (06-walrus.md §\"Configuration\"). */\nexport interface WalrusLocalClusterOptions {\n\t/** Engine row name + on-disk dir suffix + registry key.\n\t * Default `'walrus'`. */\n\treadonly name?: string;\n\t/** Number of storage-node containers. Must be `>= 1` (synchronous\n\t * factory-time guard). Default `1`. */\n\treadonly nodeCount?: number;\n\t/** Total shards distributed across the committee. Must be\n\t * `>= nodeCount`. Default `100` (distilled-doc default block). */\n\treadonly shards?: number;\n\t/** Pinned walrus release — drives the wrapper image build.\n\t * Default `'testnet-v1.49.1'`. */\n\treadonly version?: string;\n\t/** Sui release whose binary the wrapper image bakes (distilled-\n\t * doc invariant 24). Default `'devnet-v1.71.0'`. */\n\treadonly suiVersion?: string;\n\t/** Port each storage node binds inside the container. Default\n\t * 9185 (same as the router entrypoint — invariant 9). */\n\treadonly containerApiPort?: number;\n\t/** Walrus epoch length passed to `walrus-deploy --epoch-duration`.\n\t * Default `'24h'`. */\n\treadonly epochDuration?: string;\n\t/** Per-node TCP ready-probe timeout (ms). Defaults to\n\t * `DEFAULT_NODE_READY_TIMEOUT_MS`. */\n\treadonly readyTimeoutMs?: number;\n}\n\n/** Resolved local-cluster boot artifacts. */\nexport interface LocalClusterBootResult {\n\treadonly mode: 'local';\n\treadonly deploy: CachedDeployState;\n\treadonly walrusPackageId: string;\n\treadonly walPackageId: string;\n\treadonly nodes: ReadonlyArray<WalrusStorageNode>;\n\treadonly aggregatorUrl: string;\n\treadonly publisherUrl: string;\n\treadonly proxyUrl: string;\n\treadonly exchangeObjectId: string | undefined;\n\treadonly exchange: WalExchangeHandle | null;\n\t/** WAL faucet strategy — present only when the local cluster has a\n\t * non-empty exchange object. The barrel registers this onto the\n\t * `coinType:<fullCoinType>` strategy contributor decl. `null`\n\t * otherwise. */\n\treadonly walFaucetStrategy: WalFaucetStrategy | null;\n\treadonly walCoinType: string;\n}\n\n/** Defaults applied to options. */\nexport interface ResolvedLocalClusterOptions {\n\treadonly name: string;\n\treadonly nodeCount: number;\n\treadonly shards: number;\n\treadonly version: string;\n\treadonly suiVersion: string;\n\treadonly containerApiPort: number;\n\treadonly epochDuration: string;\n\treadonly readyTimeoutMs: number;\n}\n\n/** Synchronous factory-time validation. Mirrors v3's\n * `local-cluster.ts:101-121` guards. Throws (NOT Effect-fail) so\n * misconfiguration trips at the `defineDevstack` call site rather\n * than at deferred Layer.build time. Distilled-doc invariant 11. */\nexport const resolveLocalClusterOptions = (\n\topts: WalrusLocalClusterOptions,\n): ResolvedLocalClusterOptions => {\n\tconst nodeCount = expectPositiveInteger(opts.nodeCount ?? 1, {\n\t\tfield: 'nodeCount',\n\t\tmkError: ({ field, message, hint }) =>\n\t\t\twalrusConfigError(\n\t\t\t\tfield,\n\t\t\t\t`walrusLocalCluster: nodeCount must be >= 1 (got ${String(opts.nodeCount ?? 1)})`,\n\t\t\t\thint ?? message,\n\t\t\t),\n\t\thint: 'set nodeCount to a positive integer (default 1)',\n\t});\n\tif (nodeCount > WALRUS_MAX_NODE_COUNT) {\n\t\tthrow walrusConfigError(\n\t\t\t'nodeCount',\n\t\t\t`walrusLocalCluster: nodeCount (${nodeCount}) exceeds the maximum ${WALRUS_MAX_NODE_COUNT} ` +\n\t\t\t\t`pre-declared Traefik entrypoints (walrus-node-0..${WALRUS_MAX_NODE_COUNT - 1}).`,\n\t\t\t`reduce nodeCount or raise WALRUS_MAX_NODE_COUNT in plugins/walrus/routable.ts`,\n\t\t);\n\t}\n\tconst shards = expectPositiveInteger(opts.shards ?? 100, {\n\t\tfield: 'shards',\n\t\tmkError: ({ field, message, hint }) =>\n\t\t\twalrusConfigError(\n\t\t\t\tfield,\n\t\t\t\t`walrusLocalCluster: shards must be a positive integer (got ${String(opts.shards ?? 100)})`,\n\t\t\t\thint ?? message,\n\t\t\t),\n\t\thint: 'set shards to a positive integer (default 100)',\n\t});\n\tif (shards < nodeCount) {\n\t\tthrow walrusConfigError(\n\t\t\t'shards',\n\t\t\t`walrusLocalCluster: shards (${shards}) must be >= nodeCount (${nodeCount})`,\n\t\t\t`set shards >= ${nodeCount} (default 100)`,\n\t\t);\n\t}\n\treturn {\n\t\tname: opts.name ?? 'walrus',\n\t\tnodeCount,\n\t\tshards,\n\t\tversion: opts.version ?? DEFAULT_WALRUS_REF,\n\t\tsuiVersion: opts.suiVersion ?? DEFAULT_SUI_VERSION,\n\t\tcontainerApiPort: opts.containerApiPort ?? DEFAULT_CONTAINER_API_PORT,\n\t\tepochDuration: opts.epochDuration ?? '24h',\n\t\treadyTimeoutMs: opts.readyTimeoutMs ?? DEFAULT_NODE_READY_TIMEOUT_MS,\n\t};\n};\n\n/** Dependencies the local service consumes at acquire-time. */\nexport interface LocalClusterDeps {\n\treadonly runtime: ContainerRuntime;\n\treadonly publisher: ArtifactPublisher;\n\treadonly probe: ChainProbe<SuiProbeKey>;\n\treadonly suiSdk: WalSwapSdk;\n\treadonly suiChainId: ChainId;\n\treadonly suiRpcUrlInNetwork: string;\n\treadonly walrusFaucetUrlInNetwork: string;\n\treadonly waitForFundsReady: Effect.Effect<void, unknown>;\n\treadonly app: string;\n\treadonly stack: string;\n\t/** Pre-allocated /24 prefix from `subnetForStack`. */\n\treadonly subnetPrefix: string;\n\treadonly walrusNetworkName: string;\n\treadonly suiNetworkName: string;\n\treadonly deployHostMountPath: string;\n\t/** On-disk per-stack root from `StackPathsService.stackRoot`. The\n\t * walrus bind-mount is computed off this; `deployHostMountPath`\n\t * MUST live under it. */\n\treadonly stackRoot: string;\n}\n\n/** Boot the local cluster. Returns the resolved value the plugin\n * projects onto its tags.\n *\n * Steps:\n * - Image build — `resolveCargoImage` (bootstrap asset).\n * Honors `WALRUS_CARGO_IMAGE_OVERRIDE` for the pre-baked path.\n * - Docker network ensure — `runtime.ensureNetwork(walrusNet)`.\n * The sui network is owned by the sui plugin; we attach to it\n * as a secondary network on each storage node.\n * - Deploy contracts — `deployWalrusContracts` dispatches through\n * the artifact publisher primitive; the produce body runs the walrus deploy\n * one-shot.\n * - Storage nodes — parallel boot via `startStorageNodes`.\n * - Proxy URL pick — `nodes[0].rpcUrl`.\n * - WAL faucet strategy — constructed if `state.exchangeObject`\n * exists. Surfaced on the boot result; the barrel registers\n * the contributor decl.\n *\n * Per-step failures surface as `WalrusPluginError` with the phase\n * vocabulary from `errors.ts`; artifact publisher failures pass through as\n * `ArtifactPublishError`. The plugin narration vocabulary anchors\n * on these phase tags.\n */\nexport const bootLocalCluster = (\n\tdeps: LocalClusterDeps,\n\topts: ResolvedLocalClusterOptions,\n): Effect.Effect<\n\tLocalClusterBootResult,\n\tWalrusError | ArtifactPublishError,\n\tScope.Scope | FileSystem.FileSystem | Path.Path\n> =>\n\tEffect.gen(function* () {\n\t\t// ---- cargo image (bootstrap asset) -----------------------\n\t\t// The cargo image is content-addressed; the resolver owns the\n\t\t// cache check + the registry-tag override fast path.\n\t\tyield* setCurrentPluginPhase(`resolving Walrus image ${opts.version}`);\n\t\tconst walrusImage = yield* resolveCargoImage(deps.runtime, {\n\t\t\twalrusRef: opts.version,\n\t\t\tsuiVersion: opts.suiVersion,\n\t\t\towner: { app: deps.app, stack: deps.stack },\n\t\t});\n\n\t\t// ---- docker network ensure ------------------------------\n\t\tyield* setCurrentPluginPhase(`ensuring Walrus network ${deps.walrusNetworkName}`);\n\t\tyield* deps.runtime\n\t\t\t.ensureNetwork({\n\t\t\t\tname: deps.walrusNetworkName,\n\t\t\t\tapp: deps.app,\n\t\t\t\tstack: deps.stack,\n\t\t\t})\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t\t'cluster-network',\n\t\t\t\t\t\t\t`walrus: ensureNetwork('${deps.walrusNetworkName}') failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t\t{ cause },\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\n\t\t// ---- deploy via ArtifactPublisher ----------------\n\t\t// The deploy one-shot needs the walrus image + sui network so it\n\t\t// can dial the per-stack sui RPC + faucet over docker DNS.\n\t\t//\n\t\t// Per-node IP CSV is derived from the subnet prefix; per-node\n\t\t// hostnames likewise. Both must be in lockstep with the\n\t\t// storage-node boot below — the deploy step writes per-node\n\t\t// committee records on chain using these.\n\t\tconst publicHosts = Array.from({ length: opts.nodeCount }, (_, i) =>\n\t\t\tcomputePublicHostname(deps.app, deps.stack, i),\n\t\t).join(',');\n\t\tconst listeningIps = Array.from(\n\t\t\t{ length: opts.nodeCount },\n\t\t\t(_, i) => `${deps.subnetPrefix}.${WALRUS_NODE_IP_BASE + i}`,\n\t\t).join(',');\n\n\t\tyield* setCurrentPluginPhase(\n\t\t\t`deploying Walrus contracts (${opts.nodeCount} node${opts.nodeCount === 1 ? '' : 's'}, ${opts.shards} shards)`,\n\t\t);\n\t\tconst { state } = yield* deployWalrusContracts(deps.publisher, deps.probe, deps.runtime, {\n\t\t\twalrusName: opts.name,\n\t\t\tchainId: deps.suiChainId,\n\t\t\tcontentHash: brandContentHash(\n\t\t\t\t`walrus|${opts.version}|${opts.suiVersion}|${opts.nodeCount}|${opts.shards}|${opts.epochDuration}`,\n\t\t\t),\n\t\t\toutputDirHostPath: deps.deployHostMountPath,\n\t\t\tstackRoot: deps.stackRoot,\n\t\t\tsuiRpcUrlInNetwork: deps.suiRpcUrlInNetwork,\n\t\t\twalrusFaucetUrlInNetwork: deps.walrusFaucetUrlInNetwork,\n\t\t\twaitForFundsReady: deps.waitForFundsReady,\n\t\t\tcommitteeSize: opts.nodeCount,\n\t\t\tshards: opts.shards,\n\t\t\tepochDuration: opts.epochDuration,\n\t\t\tpublicHostsCsv: publicHosts,\n\t\t\tlisteningIpsCsv: listeningIps,\n\t\t\twalrusImage,\n\t\t\tsuiNetworkName: deps.suiNetworkName,\n\t\t});\n\t\tconst deployConfigHash = [\n\t\t\t'walrus-deploy',\n\t\t\tstate.walrusPackageId,\n\t\t\tstate.systemObject,\n\t\t\tstate.stakingObject,\n\t\t\tstate.exchangeObject ?? 'no-exchange',\n\t\t].join('|');\n\n\t\t// Per-node image tags. Each storage node runs under its OWN tag (a cheap\n\t\t// re-tag of the one content-cached cargo build) so its committed writable\n\t\t// layer — the RocksDB holding that node's slivers — promotes to a DISTINCT\n\t\t// image on snapshot restore. A single shared tag would make the restore\n\t\t// image-promote collapse all N committed layers onto one tag\n\t\t// (last-write-wins): N-1 nodes boot on the wrong layer and every\n\t\t// pre-snapshot blob is orphaned. The tag is scoped by the deployed\n\t\t// `walrusPackageId` — stable across boot1 -> restore -> boot2 (the deploy\n\t\t// cache reuses the same id, so the restore's promote target matches what\n\t\t// boot2 requests), but DISTINCT per fresh deployment, so a later cold boot\n\t\t// on a new chain never inherits a prior run's committed node layers (which\n\t\t// carry a stale committee and would reject writes). The base `walrusImage`\n\t\t// (shared) still backs the transient deploy one-shot (`--rm`, unsnapshotted).\n\t\tconst nodeImageScope = state.walrusPackageId.replace(/^0x/, '').slice(0, 12);\n\t\tconst nodeImages = yield* Effect.forEach(\n\t\t\tArray.from({ length: opts.nodeCount }, (_, i) => i),\n\t\t\t(i) =>\n\t\t\t\tresolveCargoImage(\n\t\t\t\t\tdeps.runtime,\n\t\t\t\t\t{\n\t\t\t\t\t\twalrusRef: opts.version,\n\t\t\t\t\t\tsuiVersion: opts.suiVersion,\n\t\t\t\t\t\towner: { app: deps.app, stack: deps.stack },\n\t\t\t\t\t},\n\t\t\t\t\t`${walrusImage.tag}-${nodeImageScope}-node-${i}`,\n\t\t\t\t),\n\t\t);\n\n\t\t// ---- storage nodes — parallel boot ----------------------\n\t\tyield* setCurrentPluginPhase(\n\t\t\t`starting ${opts.nodeCount} Walrus storage node${opts.nodeCount === 1 ? '' : 's'}`,\n\t\t);\n\t\tconst { nodes } = yield* startStorageNodes(deps.runtime, {\n\t\t\tapp: deps.app,\n\t\t\tstack: deps.stack,\n\t\t\twalrusName: opts.name,\n\t\t\timages: nodeImages,\n\t\t\tnodeCount: opts.nodeCount,\n\t\t\tsubnetPrefix: deps.subnetPrefix,\n\t\t\tcontainerApiPort: opts.containerApiPort,\n\t\t\twalrusNetworkName: deps.walrusNetworkName,\n\t\t\tsuiNetworkName: deps.suiNetworkName,\n\t\t\tdeployHostMountPath: deps.deployHostMountPath,\n\t\t\tstackRoot: deps.stackRoot,\n\t\t\tdeployConfigHash,\n\t\t\treadyTimeoutMs: opts.readyTimeoutMs,\n\t\t});\n\n\t\t// ---- proxy URL pick — nodes[0].rpcUrl -------------------\n\t\t// `nodeCount >= 1` is enforced synchronously already; this is\n\t\t// defense-in-depth.\n\t\tif (nodes.length === 0) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError('proxy', 'walrus: at least one storage node is required'),\n\t\t\t);\n\t\t}\n\t\tconst proxyUrl = nodes[0]!.rpcUrl;\n\n\t\t// ---- exchange resolution + WAL funding strategy ------\n\t\t// Register a `coinType:<fullCoinType>` strategy that swaps the\n\t\t// requesting account's SUI into WAL on demand. Accounts opt in via\n\t\t// their normal `funding` list.\n\t\tyield* setCurrentPluginPhase('resolving WAL exchange');\n\t\tconst exchange = yield* resolveWalExchange(deps.probe, state.exchangeObject);\n\t\tconst walFaucetStrategy: WalFaucetStrategy | null = exchange\n\t\t\t? makeWalFaucetStrategy({\n\t\t\t\t\texchange,\n\t\t\t\t\tsdk: deps.suiSdk,\n\t\t\t\t})\n\t\t\t: null;\n\t\tconst resolvedWalCoinType = yield* resolveWalCoinType({\n\t\t\tprobe: deps.probe,\n\t\t\ttreasuryObjectId: state.treasuryObject,\n\t\t\tdeployPackageId: state.walrusPackageId,\n\t\t\trequireTreasuryObject: exchange !== null,\n\t\t});\n\t\tconst resolvedWalPackageId = walPackageIdFromCoinType(resolvedWalCoinType);\n\n\t\treturn {\n\t\t\tmode: 'local' as const,\n\t\t\tdeploy: state,\n\t\t\twalrusPackageId: state.walrusPackageId,\n\t\t\twalPackageId: resolvedWalPackageId,\n\t\t\tnodes,\n\t\t\taggregatorUrl: proxyUrl,\n\t\t\tpublisherUrl: proxyUrl,\n\t\t\tproxyUrl,\n\t\t\texchangeObjectId: state.exchangeObject,\n\t\t\texchange,\n\t\t\twalFaucetStrategy,\n\t\t\twalCoinType: resolvedWalCoinType,\n\t\t};\n\t}).pipe(\n\t\tEffect.withSpan('devstack.plugin.walrus.localCluster.boot', {\n\t\t\tattributes: {\n\t\t\t\t[SpanAttr.plugin]: 'walrus',\n\t\t\t\t[WalrusSpans.name]: opts.name,\n\t\t\t\t[WalrusSpans.nodeCount]: opts.nodeCount,\n\t\t\t\t[WalrusSpans.shards]: opts.shards,\n\t\t\t},\n\t\t}),\n\t);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"local-cluster.mjs","names":["brandContentHash"],"sources":["../../../../src/plugins/walrus/mode/local-cluster.ts"],"sourcesContent":["// Walrus mode — local cluster.\n//\n// Distilled-doc reference (06-walrus.md §\"Lifecycle: Startup —\n// local cluster\"). Eight ordered phases:\n//\n// 0. Yield deps (Sui, Identity, ChainProbe, faucet strategy opt).\n// 1. Image build — upstream cargo image (bootstrap asset) +\n// wrapper image (inline; content-addressed on\n// the upstream tag + suiVersion).\n// 1b. Docker network create — per-stack `/24` via\n// `Docker.networkCreate(networkName, {subnet})`.\n// 2. Deploy contracts — via `ArtifactPublisher`. The\n// publisher folds chainId into the cache\n// key; verify probes BOTH the on-disk\n// `deploy` file AND on-chain object\n// existence; produce runs the deploy\n// one-shot.\n// 3. Register committee — omitted entirely (no placeholder).\n// 4. Storage nodes — parallel boot of N storage-node containers.\n// 5. Exchange resolution — on-chain getObject + parse type.\n// Degrades to undefined on\n// OBJECT_NOT_FOUND.\n// 6. Proxy URL pick — nodes[0].rpcUrl is the representative\n// aggregator/publisher.\n// 7a. WAL faucet strategy register — opt-in when an exchange exists.\n// 8. Registries — package + endpoint + walrus-state.\n//\n// What this file owns: the dispatch shape + the typed options\n// surface + the synchronous factory-time validation.\n//\n// What this file delegates: container/Move heavy paths live in\n// `storage-nodes.ts`, `deploy.ts`, and the `ArtifactPublisher`\n// primitive.\n\nimport { Effect, FileSystem, Path, type Scope } from 'effect';\n\nimport type {\n\tArtifactPublishError,\n\tArtifactPublisher,\n} from '../../../primitives/artifact-publisher.ts';\nimport type { ChainProbe } from '../../../contracts/chain-probe.ts';\nimport type { ContainerRuntime } from '../../../contracts/container-runtime.ts';\nimport type { SuiProbeKey } from '../../sui/index.ts';\nimport { contentHash as brandContentHash } from '../../../substrate/brand.ts';\nimport { expectPositiveInteger } from '../../../substrate/runtime/config-validation.ts';\nimport { setCurrentPluginPhase } from '../../../substrate/runtime/current-plugin.ts';\nimport { walrusConfigError, walrusPluginError, type WalrusError } from '../errors.ts';\nimport { WALRUS_MAX_NODE_COUNT } from '../routable.ts';\nimport type { WalrusStorageNode } from '../storage-nodes.ts';\nimport {\n\tDEFAULT_NODE_READY_TIMEOUT_MS,\n\tDEFAULT_CONTAINER_API_PORT,\n\tWALRUS_NODE_IP_BASE,\n\tcomputePublicHostname,\n\tstartStorageNodes,\n} from '../storage-nodes.ts';\nimport { deployWalrusContracts, type CachedDeployState } from '../deploy.ts';\nimport {\n\tDEFAULT_SUI_VERSION,\n\tDEFAULT_WALRUS_REF,\n\tresolveCargoImage,\n} from '../bootstrap-assets/cargo-image.ts';\nimport {\n\tmakeWalFaucetStrategy,\n\twalPackageIdFromCoinType,\n\tresolveWalCoinType,\n\ttype WalFaucetStrategy,\n} from '../faucet-strategy.ts';\nimport { resolveWalExchange, type WalExchangeHandle, type WalSwapSdk } from '../wal-swap.ts';\n\n/** Options for the local-cluster mode (06-walrus.md\n * §\"Configuration\"). */\nexport interface WalrusLocalClusterOptions {\n\t/** Engine row name + on-disk dir suffix + registry key.\n\t * Default `'walrus'`. */\n\treadonly name?: string;\n\t/** Number of storage-node containers. Must be `>= 1` (synchronous\n\t * factory-time guard). Default `1`. */\n\treadonly nodeCount?: number;\n\t/** Total shards distributed across the committee. Must be\n\t * `>= nodeCount`. Default `100` (distilled-doc default block). */\n\treadonly shards?: number;\n\t/** Pinned walrus release — drives the wrapper image build.\n\t * Default `'testnet-v1.49.1'`. */\n\treadonly version?: string;\n\t/** Sui release whose binary the wrapper image bakes (distilled-\n\t * doc invariant 24). Default `'devnet-v1.71.0'`. */\n\treadonly suiVersion?: string;\n\t/** Port each storage node binds inside the container. Default\n\t * 9185 (same as the router entrypoint — invariant 9). */\n\treadonly containerApiPort?: number;\n\t/** Walrus epoch length passed to `walrus-deploy --epoch-duration`.\n\t * Default `'24h'`. */\n\treadonly epochDuration?: string;\n\t/** Per-node TCP ready-probe timeout (ms). Defaults to\n\t * `DEFAULT_NODE_READY_TIMEOUT_MS`. */\n\treadonly readyTimeoutMs?: number;\n}\n\n/** Resolved local-cluster boot artifacts. */\nexport interface LocalClusterBootResult {\n\treadonly mode: 'local';\n\treadonly deploy: CachedDeployState;\n\treadonly walrusPackageId: string;\n\treadonly walPackageId: string;\n\treadonly nodes: ReadonlyArray<WalrusStorageNode>;\n\treadonly aggregatorUrl: string;\n\treadonly publisherUrl: string;\n\treadonly proxyUrl: string;\n\treadonly exchangeObjectId: string | undefined;\n\treadonly exchange: WalExchangeHandle | null;\n\t/** WAL faucet strategy — present only when the local cluster has a\n\t * non-empty exchange object. The barrel registers this onto the\n\t * `coinType:<fullCoinType>` strategy contributor decl. `null`\n\t * otherwise. */\n\treadonly walFaucetStrategy: WalFaucetStrategy | null;\n\treadonly walCoinType: string;\n}\n\n/** Defaults applied to options. */\nexport interface ResolvedLocalClusterOptions {\n\treadonly name: string;\n\treadonly nodeCount: number;\n\treadonly shards: number;\n\treadonly version: string;\n\treadonly suiVersion: string;\n\treadonly containerApiPort: number;\n\treadonly epochDuration: string;\n\treadonly readyTimeoutMs: number;\n}\n\n/** Synchronous factory-time validation. Throws (NOT Effect-fail) so\n * misconfiguration trips at the `defineDevstack` call site rather\n * than at deferred Layer.build time. Distilled-doc invariant 11. */\nexport const resolveLocalClusterOptions = (\n\topts: WalrusLocalClusterOptions,\n): ResolvedLocalClusterOptions => {\n\tconst nodeCount = expectPositiveInteger(opts.nodeCount ?? 1, {\n\t\tfield: 'nodeCount',\n\t\tmkError: ({ field, message, hint }) =>\n\t\t\twalrusConfigError(\n\t\t\t\tfield,\n\t\t\t\t`walrusLocalCluster: nodeCount must be >= 1 (got ${String(opts.nodeCount ?? 1)})`,\n\t\t\t\thint ?? message,\n\t\t\t),\n\t\thint: 'set nodeCount to a positive integer (default 1)',\n\t});\n\tif (nodeCount > WALRUS_MAX_NODE_COUNT) {\n\t\tthrow walrusConfigError(\n\t\t\t'nodeCount',\n\t\t\t`walrusLocalCluster: nodeCount (${nodeCount}) exceeds the maximum ${WALRUS_MAX_NODE_COUNT} ` +\n\t\t\t\t`pre-declared Traefik entrypoints (walrus-node-0..${WALRUS_MAX_NODE_COUNT - 1}).`,\n\t\t\t`reduce nodeCount or raise WALRUS_MAX_NODE_COUNT in plugins/walrus/routable.ts`,\n\t\t);\n\t}\n\tconst shards = expectPositiveInteger(opts.shards ?? 100, {\n\t\tfield: 'shards',\n\t\tmkError: ({ field, message, hint }) =>\n\t\t\twalrusConfigError(\n\t\t\t\tfield,\n\t\t\t\t`walrusLocalCluster: shards must be a positive integer (got ${String(opts.shards ?? 100)})`,\n\t\t\t\thint ?? message,\n\t\t\t),\n\t\thint: 'set shards to a positive integer (default 100)',\n\t});\n\tif (shards < nodeCount) {\n\t\tthrow walrusConfigError(\n\t\t\t'shards',\n\t\t\t`walrusLocalCluster: shards (${shards}) must be >= nodeCount (${nodeCount})`,\n\t\t\t`set shards >= ${nodeCount} (default 100)`,\n\t\t);\n\t}\n\treturn {\n\t\tname: opts.name ?? 'walrus',\n\t\tnodeCount,\n\t\tshards,\n\t\tversion: opts.version ?? DEFAULT_WALRUS_REF,\n\t\tsuiVersion: opts.suiVersion ?? DEFAULT_SUI_VERSION,\n\t\tcontainerApiPort: opts.containerApiPort ?? DEFAULT_CONTAINER_API_PORT,\n\t\tepochDuration: opts.epochDuration ?? '24h',\n\t\treadyTimeoutMs: opts.readyTimeoutMs ?? DEFAULT_NODE_READY_TIMEOUT_MS,\n\t};\n};\n\n/** Dependencies the local service consumes at acquire-time. */\nexport interface LocalClusterDeps {\n\treadonly runtime: ContainerRuntime;\n\treadonly publisher: ArtifactPublisher;\n\treadonly probe: ChainProbe<SuiProbeKey>;\n\treadonly suiSdk: WalSwapSdk;\n\treadonly suiChainId: string;\n\treadonly suiRpcUrlInNetwork: string;\n\treadonly walrusFaucetUrlInNetwork: string;\n\treadonly waitForFundsReady: Effect.Effect<void, unknown>;\n\treadonly app: string;\n\treadonly stack: string;\n\t/** Pre-allocated /24 prefix from `subnetForStack`. */\n\treadonly subnetPrefix: string;\n\treadonly walrusNetworkName: string;\n\treadonly suiNetworkName: string;\n\treadonly deployHostMountPath: string;\n\t/** On-disk per-stack root from `StackPathsService.stackRoot`. The\n\t * walrus bind-mount is computed off this; `deployHostMountPath`\n\t * MUST live under it. */\n\treadonly stackRoot: string;\n}\n\n/** Boot the local cluster. Returns the resolved value the plugin\n * projects onto its tags.\n *\n * Steps:\n * - Image build — `resolveCargoImage` (bootstrap asset).\n * Honors `WALRUS_CARGO_IMAGE_OVERRIDE` for the pre-baked path.\n * - Docker network ensure — `runtime.ensureNetwork(walrusNet)`.\n * The sui network is owned by the sui plugin; we attach to it\n * as a secondary network on each storage node.\n * - Deploy contracts — `deployWalrusContracts` dispatches through\n * the artifact publisher primitive; the produce body runs the walrus deploy\n * one-shot.\n * - Storage nodes — parallel boot via `startStorageNodes`.\n * - Proxy URL pick — `nodes[0].rpcUrl`.\n * - WAL faucet strategy — constructed if `state.exchangeObject`\n * exists. Surfaced on the boot result; the barrel registers\n * the contributor decl.\n *\n * Per-step failures surface as `WalrusPluginError` with the phase\n * vocabulary from `errors.ts`; artifact publisher failures pass through as\n * `ArtifactPublishError`. The plugin narration vocabulary anchors\n * on these phase tags.\n */\nexport const bootLocalCluster = (\n\tdeps: LocalClusterDeps,\n\topts: ResolvedLocalClusterOptions,\n): Effect.Effect<\n\tLocalClusterBootResult,\n\tWalrusError | ArtifactPublishError,\n\tScope.Scope | FileSystem.FileSystem | Path.Path\n> =>\n\tEffect.gen(function* () {\n\t\t// ---- cargo image (bootstrap asset) -----------------------\n\t\t// The cargo image is content-addressed; the resolver owns the\n\t\t// cache check + the registry-tag override fast path.\n\t\tyield* setCurrentPluginPhase(`resolving Walrus image ${opts.version}`);\n\t\tconst walrusImage = yield* resolveCargoImage(deps.runtime, {\n\t\t\twalrusRef: opts.version,\n\t\t\tsuiVersion: opts.suiVersion,\n\t\t\towner: { app: deps.app, stack: deps.stack },\n\t\t});\n\n\t\t// ---- docker network ensure ------------------------------\n\t\tyield* setCurrentPluginPhase(`ensuring Walrus network ${deps.walrusNetworkName}`);\n\t\tyield* deps.runtime\n\t\t\t.ensureNetwork({\n\t\t\t\tname: deps.walrusNetworkName,\n\t\t\t\tapp: deps.app,\n\t\t\t\tstack: deps.stack,\n\t\t\t})\n\t\t\t.pipe(\n\t\t\t\tEffect.catch((cause) =>\n\t\t\t\t\tEffect.fail(\n\t\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t\t'cluster-network',\n\t\t\t\t\t\t\t`walrus: ensureNetwork('${deps.walrusNetworkName}') failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t\t{ cause },\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\n\t\t// ---- deploy via ArtifactPublisher ----------------\n\t\t// The deploy one-shot needs the walrus image + sui network so it\n\t\t// can dial the per-stack sui RPC + faucet over docker DNS.\n\t\t//\n\t\t// Per-node IP CSV is derived from the subnet prefix; per-node\n\t\t// hostnames likewise. Both must be in lockstep with the\n\t\t// storage-node boot below — the deploy step writes per-node\n\t\t// committee records on chain using these.\n\t\tconst publicHosts = Array.from({ length: opts.nodeCount }, (_, i) =>\n\t\t\tcomputePublicHostname(deps.app, deps.stack, i),\n\t\t).join(',');\n\t\tconst listeningIps = Array.from(\n\t\t\t{ length: opts.nodeCount },\n\t\t\t(_, i) => `${deps.subnetPrefix}.${WALRUS_NODE_IP_BASE + i}`,\n\t\t).join(',');\n\n\t\tyield* setCurrentPluginPhase(\n\t\t\t`deploying Walrus contracts (${opts.nodeCount} node${opts.nodeCount === 1 ? '' : 's'}, ${opts.shards} shards)`,\n\t\t);\n\t\tconst { state } = yield* deployWalrusContracts(deps.publisher, deps.probe, deps.runtime, {\n\t\t\twalrusName: opts.name,\n\t\t\tchainId: deps.suiChainId,\n\t\t\tcontentHash: brandContentHash(\n\t\t\t\t`walrus|${opts.version}|${opts.suiVersion}|${opts.nodeCount}|${opts.shards}|${opts.epochDuration}`,\n\t\t\t),\n\t\t\toutputDirHostPath: deps.deployHostMountPath,\n\t\t\tstackRoot: deps.stackRoot,\n\t\t\tsuiRpcUrlInNetwork: deps.suiRpcUrlInNetwork,\n\t\t\twalrusFaucetUrlInNetwork: deps.walrusFaucetUrlInNetwork,\n\t\t\twaitForFundsReady: deps.waitForFundsReady,\n\t\t\tcommitteeSize: opts.nodeCount,\n\t\t\tshards: opts.shards,\n\t\t\tepochDuration: opts.epochDuration,\n\t\t\tpublicHostsCsv: publicHosts,\n\t\t\tlisteningIpsCsv: listeningIps,\n\t\t\twalrusImage,\n\t\t\tsuiNetworkName: deps.suiNetworkName,\n\t\t});\n\t\tconst deployConfigHash = [\n\t\t\t'walrus-deploy',\n\t\t\tstate.walrusPackageId,\n\t\t\tstate.systemObject,\n\t\t\tstate.stakingObject,\n\t\t\tstate.exchangeObject ?? 'no-exchange',\n\t\t].join('|');\n\n\t\t// Per-node image tags. Each storage node runs under its OWN tag (a cheap\n\t\t// re-tag of the one content-cached cargo build) so its committed writable\n\t\t// layer — the RocksDB holding that node's slivers — promotes to a DISTINCT\n\t\t// image on snapshot restore. A single shared tag would make the restore\n\t\t// image-promote collapse all N committed layers onto one tag\n\t\t// (last-write-wins): N-1 nodes boot on the wrong layer and every\n\t\t// pre-snapshot blob is orphaned. The tag is scoped by the deployed\n\t\t// `walrusPackageId` — stable across boot1 -> restore -> boot2 (the deploy\n\t\t// cache reuses the same id, so the restore's promote target matches what\n\t\t// boot2 requests), but DISTINCT per fresh deployment, so a later cold boot\n\t\t// on a new chain never inherits a prior run's committed node layers (which\n\t\t// carry a stale committee and would reject writes). The base `walrusImage`\n\t\t// (shared) still backs the transient deploy one-shot (`--rm`, unsnapshotted).\n\t\tconst nodeImageScope = state.walrusPackageId.replace(/^0x/, '').slice(0, 12);\n\t\tconst nodeImages = yield* Effect.forEach(\n\t\t\tArray.from({ length: opts.nodeCount }, (_, i) => i),\n\t\t\t(i) =>\n\t\t\t\tresolveCargoImage(\n\t\t\t\t\tdeps.runtime,\n\t\t\t\t\t{\n\t\t\t\t\t\twalrusRef: opts.version,\n\t\t\t\t\t\tsuiVersion: opts.suiVersion,\n\t\t\t\t\t\towner: { app: deps.app, stack: deps.stack },\n\t\t\t\t\t},\n\t\t\t\t\t`${walrusImage.tag}-${nodeImageScope}-node-${i}`,\n\t\t\t\t),\n\t\t);\n\n\t\t// ---- storage nodes — parallel boot ----------------------\n\t\tyield* setCurrentPluginPhase(\n\t\t\t`starting ${opts.nodeCount} Walrus storage node${opts.nodeCount === 1 ? '' : 's'}`,\n\t\t);\n\t\tconst { nodes } = yield* startStorageNodes(deps.runtime, {\n\t\t\tapp: deps.app,\n\t\t\tstack: deps.stack,\n\t\t\twalrusName: opts.name,\n\t\t\timages: nodeImages,\n\t\t\tnodeCount: opts.nodeCount,\n\t\t\tsubnetPrefix: deps.subnetPrefix,\n\t\t\tcontainerApiPort: opts.containerApiPort,\n\t\t\twalrusNetworkName: deps.walrusNetworkName,\n\t\t\tsuiNetworkName: deps.suiNetworkName,\n\t\t\tdeployHostMountPath: deps.deployHostMountPath,\n\t\t\tstackRoot: deps.stackRoot,\n\t\t\tdeployConfigHash,\n\t\t\treadyTimeoutMs: opts.readyTimeoutMs,\n\t\t});\n\n\t\t// ---- proxy URL pick — nodes[0].rpcUrl -------------------\n\t\t// `nodeCount >= 1` is enforced synchronously already; this is\n\t\t// defense-in-depth.\n\t\tif (nodes.length === 0) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError('proxy', 'walrus: at least one storage node is required'),\n\t\t\t);\n\t\t}\n\t\tconst proxyUrl = nodes[0]!.rpcUrl;\n\n\t\t// ---- exchange resolution + WAL funding strategy ------\n\t\t// Register a `coinType:<fullCoinType>` strategy that swaps the\n\t\t// requesting account's SUI into WAL on demand. Accounts opt in via\n\t\t// their normal `funding` list.\n\t\tyield* setCurrentPluginPhase('resolving WAL exchange');\n\t\tconst exchange = yield* resolveWalExchange(deps.probe, state.exchangeObject);\n\t\tconst walFaucetStrategy: WalFaucetStrategy | null = exchange\n\t\t\t? makeWalFaucetStrategy({\n\t\t\t\t\texchange,\n\t\t\t\t\tsdk: deps.suiSdk,\n\t\t\t\t})\n\t\t\t: null;\n\t\tconst resolvedWalCoinType = yield* resolveWalCoinType({\n\t\t\tprobe: deps.probe,\n\t\t\ttreasuryObjectId: state.treasuryObject,\n\t\t\tdeployPackageId: state.walrusPackageId,\n\t\t\trequireTreasuryObject: exchange !== null,\n\t\t});\n\t\tconst resolvedWalPackageId = walPackageIdFromCoinType(resolvedWalCoinType);\n\n\t\treturn {\n\t\t\tmode: 'local' as const,\n\t\t\tdeploy: state,\n\t\t\twalrusPackageId: state.walrusPackageId,\n\t\t\twalPackageId: resolvedWalPackageId,\n\t\t\tnodes,\n\t\t\taggregatorUrl: proxyUrl,\n\t\t\tpublisherUrl: proxyUrl,\n\t\t\tproxyUrl,\n\t\t\texchangeObjectId: state.exchangeObject,\n\t\t\texchange,\n\t\t\twalFaucetStrategy,\n\t\t\twalCoinType: resolvedWalCoinType,\n\t\t};\n\t});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-key.mjs","names":[],"sources":["../../../src/plugins/walrus/plugin-key.ts"],"sourcesContent":["import { pluginKey, type PluginKey } from '../../substrate/brand.ts';\n\nexport const walrusPluginKey = (name: string): PluginKey => pluginKey(`walrus:${name}`);\n"],"mappings":";;AAEA,MAAa,mBAAmB,SAA4B,UAAU,UAAU,
|
|
1
|
+
{"version":3,"file":"plugin-key.mjs","names":[],"sources":["../../../src/plugins/walrus/plugin-key.ts"],"sourcesContent":["import { pluginKey, type PluginKey } from '../../substrate/brand.ts';\n\nexport const walrusPluginKey = (name: string): PluginKey => pluginKey(`walrus:${name}`);\n"],"mappings":";;AAEA,MAAa,mBAAmB,SAA4B,UAAU,UAAU,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry-publish.mjs","names":[],"sources":["../../../src/plugins/walrus/registry-publish.ts"],"sourcesContent":["// Walrus registry publish — mode-based registry contribution shapes.\n//\n// This file is the runtime publishing layer for the downstream registries:\n//\n// - WalrusStateRegistry — `{name, systemObjectId}` entry. Local\n// uses `opts.name`; known uses the fixed\n// `'walrusKnownDeployment'`.\n// - EndpointRegistry — local publishes `walrus-aggregator` +\n// `walrus-publisher` + N × `walrus-node-<i>`.\n// Known publishes nothing (the URLs ride\n// on the WalrusResolved value).\n// - PackageRegistry — local only: `walrus.<name>` entry.\n//\n// Following the package plugin's pattern, contributions land via\n// `StrategyContributor` capability keys; the orchestrator dispatches\n// by key. This file declares the *contribution shapes*; the actual\n// `Register` closures live with the local-cluster acquire path where the resolved\n// values are bound.\n\n/** Capability-key constant for the per-stack Walrus state registry. */\nexport const WALRUS_STATE_REGISTRY_KEY = 'walrus-state-registry' as const;\n\n/** Capability-key constant for the per-stack endpoint registry —\n * shared across plugins (matches faucet/coin/etc.). */\nexport const ENDPOINT_REGISTRY_KEY = 'endpoint-registry' as const;\n\n/** Capability-key constant for the per-stack package registry —\n * mirrors `plugins/package/registry.ts`'s\n * `PACKAGE_REGISTRY_CAPABILITY_KEY` but typed independently here so\n * Walrus doesn't take a direct dep on the package plugin's internals.\n * Same string value — substrate dispatches by string equality. */\nexport const PACKAGE_REGISTRY_KEY = 'package-registry' as const;\n\n/** Local-cluster's state registry entry. The `name` field is the\n * factory's `name` option (default: `'walrus'`); two walrus\n * instances in one stack publish under disjoint names. */\nexport interface WalrusLocalStateEntry {\n\treadonly name: string;\n\treadonly systemObjectId: string;\n\treadonly stakingObjectId: string;\n\treadonly walrusPackageId: string;\n\treadonly exchangeObjectId?: string;\n}\n\n/** Known-deployment's state registry entry. The `name` is always\n * `'walrusKnownDeployment'` (distilled-doc invariant: this factory\n * does not vary by user-supplied name). */\nexport interface WalrusKnownStateEntry {\n\treadonly name: 'walrusKnownDeployment';\n\treadonly systemObjectId: string;\n\treadonly stakingObjectId: string;\n\treadonly
|
|
1
|
+
{"version":3,"file":"registry-publish.mjs","names":[],"sources":["../../../src/plugins/walrus/registry-publish.ts"],"sourcesContent":["// Walrus registry publish — mode-based registry contribution shapes.\n//\n// This file is the runtime publishing layer for the downstream registries:\n//\n// - WalrusStateRegistry — `{name, systemObjectId}` entry. Local\n// uses `opts.name`; known uses the fixed\n// `'walrusKnownDeployment'`.\n// - EndpointRegistry — local publishes `walrus-aggregator` +\n// `walrus-publisher` + N × `walrus-node-<i>`.\n// Known publishes nothing (the URLs ride\n// on the WalrusResolved value).\n// - PackageRegistry — local only: `walrus.<name>` entry.\n//\n// Following the package plugin's pattern, contributions land via\n// `StrategyContributor` capability keys; the orchestrator dispatches\n// by key. This file declares the *contribution shapes*; the actual\n// `Register` closures live with the local-cluster acquire path where the resolved\n// values are bound.\n\n/** Capability-key constant for the per-stack Walrus state registry. */\nexport const WALRUS_STATE_REGISTRY_KEY = 'walrus-state-registry' as const;\n\n/** Capability-key constant for the per-stack endpoint registry —\n * shared across plugins (matches faucet/coin/etc.). */\nexport const ENDPOINT_REGISTRY_KEY = 'endpoint-registry' as const;\n\n/** Capability-key constant for the per-stack package registry —\n * mirrors `plugins/package/registry.ts`'s\n * `PACKAGE_REGISTRY_CAPABILITY_KEY` but typed independently here so\n * Walrus doesn't take a direct dep on the package plugin's internals.\n * Same string value — substrate dispatches by string equality. */\nexport const PACKAGE_REGISTRY_KEY = 'package-registry' as const;\n\n/** Local-cluster's state registry entry. The `name` field is the\n * factory's `name` option (default: `'walrus'`); two walrus\n * instances in one stack publish under disjoint names. */\nexport interface WalrusLocalStateEntry {\n\treadonly name: string;\n\treadonly systemObjectId: string;\n\treadonly stakingObjectId: string;\n\treadonly walrusPackageId: string;\n\treadonly exchangeObjectId?: string;\n}\n\n/** Known-deployment's state registry entry. The `name` is always\n * `'walrusKnownDeployment'` (distilled-doc invariant: this factory\n * does not vary by user-supplied name). */\nexport interface WalrusKnownStateEntry {\n\treadonly name: 'walrusKnownDeployment';\n\treadonly systemObjectId: string;\n\treadonly stakingObjectId: string;\n\treadonly network: string;\n}\n\nexport type WalrusStateEntry = WalrusLocalStateEntry | WalrusKnownStateEntry;\n"],"mappings":";;AAoBA,MAAa,4BAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routable.mjs","names":[],"sources":["../../../src/plugins/walrus/routable.ts"],"sourcesContent":["// Walrus plugin — Routable contributions.\n//\n// Distilled-doc reference (06-walrus.md §\"Routes registered\"):\n// each storage node carries one Traefik route. The router binds host\n// port 9185 once globally and dispatches by `Host:` header to the\n// per-stack backend — `routerHostname(identity, 'walrus-node-<i>')`.\n//\n// For the local cluster:\n// - N × `walrus-node-<i>` routes — one per storage node, with\n// `cors: true` (walrus storage REST API lacks CORS headers).\n// - 1 × `walrus-aggregator` alias — same backend as `walrus-node-0`,\n// surfaces the conventional alias for SDK consumers.\n// - 1 × `walrus-publisher` alias — collapsed onto the same backend\n// (distilled-doc §\"Endpoints\" — \"collapsed onto a single Traefik\n// vhost\").\n//\n// Known-deployment publishes no routes — the aggregator/publisher\n// URLs land on the codegen-emitted `WalrusBindings.{aggregator,\n// publisher}Url` instead.\n\nimport type { EntrypointDecl, RoutableDecl } from '../../contracts/routable.ts';\nimport { WALRUS_ROUTER_PORT } from './storage-nodes.ts';\n\nexport const WALRUS_NODE_ENDPOINT_PREFIX = 'walrus-node-' as const;\nexport const WALRUS_AGGREGATOR_ENDPOINT_NAME = 'walrus-aggregator' as const;\nexport const WALRUS_PUBLISHER_ENDPOINT_NAME = 'walrus-publisher' as const;\n\n/** Upper bound on `nodeCount` — Traefik entrypoints are bound at boot,\n * so the cluster's per-node routes need pre-declared entrypoint names.\n * Validated at factory time in `mode/local-cluster.ts:resolveOptions`. */\nexport const WALRUS_MAX_NODE_COUNT = 8;\n\nexport const WALRUS_ENTRYPOINTS: ReadonlyArray<EntrypointDecl> = [\n\t...Array.from(\n\t\t{ length: WALRUS_MAX_NODE_COUNT },\n\t\t(_, i): EntrypointDecl => ({\n\t\t\tname: `${WALRUS_NODE_ENDPOINT_PREFIX}${i}`,\n\t\t\tport: WALRUS_ROUTER_PORT,\n\t\t\tprotocol: 'http',\n\t\t}),\n\t),\n\t{ name: WALRUS_AGGREGATOR_ENDPOINT_NAME, port: WALRUS_ROUTER_PORT, protocol: 'http' },\n\t{ name: WALRUS_PUBLISHER_ENDPOINT_NAME, port: WALRUS_ROUTER_PORT, protocol: 'http' },\n];\n\n/** Build the Routable contributions for the local cluster. `nodeCount`\n * drives the per-node fan-out; the plugin's service key + route role\n * identify the dispatch target. */\nexport const makeLocalRoutables = (args: {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly walrusName: string;\n\treadonly serviceKey: string;\n\treadonly nodeCount: number;\n\treadonly containerApiPort?: number;\n}): ReadonlyArray<RoutableDecl> => {\n\tconst containerPort = args.containerApiPort ?? WALRUS_ROUTER_PORT;\n\tconst containerNameFor = (i: number): string =>\n\t\t`devstack-${args.app}-${args.stack}-walrus-${args.walrusName}-node-${i}`;\n\tconst perNodeRoutes: ReadonlyArray<RoutableDecl> = Array.from(\n\t\t{ length: args.nodeCount },\n\t\t(_, i): RoutableDecl => ({\n\t\t\tkind: 'routable',\n\t\t\tendpointName: `${WALRUS_NODE_ENDPOINT_PREFIX}${i}`,\n\t\t\tdispatchId: {\n\t\t\t\tserviceKey: args.serviceKey,\n\t\t\t\trole: `${WALRUS_NODE_ENDPOINT_PREFIX}${i}`,\n\t\t\t},\n\t\t\tupstream: {\n\t\t\t\ttype: 'container',\n\t\t\t\tcontainerName: containerNameFor(i),\n\t\t\t\tcontainerPort,\n\t\t\t},\n\t\t\t// Distilled-doc §\"Routes registered\": cors: true (walrus\n\t\t\t// storage REST API lacks CORS headers).\n\t\t\tcors: true,\n\t\t\twireProtocol: 'http',\n\t\t}),\n\t);\n\n\t// Aggregator + publisher aliases — collapsed onto node-0 per the\n\t// distilled doc. The aggregator and publisher are conventional\n\t// endpoint names that downstream HTTP consumers look up via the\n\t// substrate's endpoint registry.\n\tconst aggregator: RoutableDecl = {\n\t\tkind: 'routable',\n\t\tendpointName: WALRUS_AGGREGATOR_ENDPOINT_NAME,\n\t\tdispatchId: {\n\t\t\tserviceKey: args.serviceKey,\n\t\t\trole: WALRUS_AGGREGATOR_ENDPOINT_NAME,\n\t\t},\n\t\tupstream: { type: 'container', containerName: containerNameFor(0), containerPort },\n\t\tcors: true,\n\t\twireProtocol: 'http',\n\t};\n\tconst publisher: RoutableDecl = {\n\t\tkind: 'routable',\n\t\tendpointName: WALRUS_PUBLISHER_ENDPOINT_NAME,\n\t\tdispatchId: {\n\t\t\tserviceKey: args.serviceKey,\n\t\t\trole: WALRUS_PUBLISHER_ENDPOINT_NAME,\n\t\t},\n\t\tupstream: { type: 'container', containerName: containerNameFor(0), containerPort },\n\t\tcors: true,\n\t\twireProtocol: 'http',\n\t};\n\n\treturn [...perNodeRoutes, aggregator, publisher];\n};\n"],"mappings":";;AAuBA,MAAa,8BAA8B;AAC3C,MAAa,kCAAkC;AAC/C,MAAa,iCAAiC;AAO9C,MAAa,qBAAoD;CAChE,GAAG,MAAM,KACR,EAAE,QAAA,
|
|
1
|
+
{"version":3,"file":"routable.mjs","names":[],"sources":["../../../src/plugins/walrus/routable.ts"],"sourcesContent":["// Walrus plugin — Routable contributions.\n//\n// Distilled-doc reference (06-walrus.md §\"Routes registered\"):\n// each storage node carries one Traefik route. The router binds host\n// port 9185 once globally and dispatches by `Host:` header to the\n// per-stack backend — `routerHostname(identity, 'walrus-node-<i>')`.\n//\n// For the local cluster:\n// - N × `walrus-node-<i>` routes — one per storage node, with\n// `cors: true` (walrus storage REST API lacks CORS headers).\n// - 1 × `walrus-aggregator` alias — same backend as `walrus-node-0`,\n// surfaces the conventional alias for SDK consumers.\n// - 1 × `walrus-publisher` alias — collapsed onto the same backend\n// (distilled-doc §\"Endpoints\" — \"collapsed onto a single Traefik\n// vhost\").\n//\n// Known-deployment publishes no routes — the aggregator/publisher\n// URLs land on the codegen-emitted `WalrusBindings.{aggregator,\n// publisher}Url` instead.\n\nimport type { EntrypointDecl, RoutableDecl } from '../../contracts/routable.ts';\nimport { WALRUS_ROUTER_PORT } from './storage-nodes.ts';\n\nexport const WALRUS_NODE_ENDPOINT_PREFIX = 'walrus-node-' as const;\nexport const WALRUS_AGGREGATOR_ENDPOINT_NAME = 'walrus-aggregator' as const;\nexport const WALRUS_PUBLISHER_ENDPOINT_NAME = 'walrus-publisher' as const;\n\n/** Upper bound on `nodeCount` — Traefik entrypoints are bound at boot,\n * so the cluster's per-node routes need pre-declared entrypoint names.\n * Validated at factory time in `mode/local-cluster.ts:resolveOptions`. */\nexport const WALRUS_MAX_NODE_COUNT = 8;\n\nexport const WALRUS_ENTRYPOINTS: ReadonlyArray<EntrypointDecl> = [\n\t...Array.from(\n\t\t{ length: WALRUS_MAX_NODE_COUNT },\n\t\t(_, i): EntrypointDecl => ({\n\t\t\tname: `${WALRUS_NODE_ENDPOINT_PREFIX}${i}`,\n\t\t\tport: WALRUS_ROUTER_PORT,\n\t\t\tprotocol: 'http',\n\t\t}),\n\t),\n\t{ name: WALRUS_AGGREGATOR_ENDPOINT_NAME, port: WALRUS_ROUTER_PORT, protocol: 'http' },\n\t{ name: WALRUS_PUBLISHER_ENDPOINT_NAME, port: WALRUS_ROUTER_PORT, protocol: 'http' },\n];\n\n/** Build the Routable contributions for the local cluster. `nodeCount`\n * drives the per-node fan-out; the plugin's service key + route role\n * identify the dispatch target. */\nexport const makeLocalRoutables = (args: {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly walrusName: string;\n\treadonly serviceKey: string;\n\treadonly nodeCount: number;\n\treadonly containerApiPort?: number;\n}): ReadonlyArray<RoutableDecl> => {\n\tconst containerPort = args.containerApiPort ?? WALRUS_ROUTER_PORT;\n\tconst containerNameFor = (i: number): string =>\n\t\t`devstack-${args.app}-${args.stack}-walrus-${args.walrusName}-node-${i}`;\n\tconst perNodeRoutes: ReadonlyArray<RoutableDecl> = Array.from(\n\t\t{ length: args.nodeCount },\n\t\t(_, i): RoutableDecl => ({\n\t\t\tkind: 'routable',\n\t\t\tendpointName: `${WALRUS_NODE_ENDPOINT_PREFIX}${i}`,\n\t\t\tdispatchId: {\n\t\t\t\tserviceKey: args.serviceKey,\n\t\t\t\trole: `${WALRUS_NODE_ENDPOINT_PREFIX}${i}`,\n\t\t\t},\n\t\t\tupstream: {\n\t\t\t\ttype: 'container',\n\t\t\t\tcontainerName: containerNameFor(i),\n\t\t\t\tcontainerPort,\n\t\t\t},\n\t\t\t// Distilled-doc §\"Routes registered\": cors: true (walrus\n\t\t\t// storage REST API lacks CORS headers).\n\t\t\tcors: true,\n\t\t\twireProtocol: 'http',\n\t\t}),\n\t);\n\n\t// Aggregator + publisher aliases — collapsed onto node-0 per the\n\t// distilled doc. The aggregator and publisher are conventional\n\t// endpoint names that downstream HTTP consumers look up via the\n\t// substrate's endpoint registry.\n\tconst aggregator: RoutableDecl = {\n\t\tkind: 'routable',\n\t\tendpointName: WALRUS_AGGREGATOR_ENDPOINT_NAME,\n\t\tdispatchId: {\n\t\t\tserviceKey: args.serviceKey,\n\t\t\trole: WALRUS_AGGREGATOR_ENDPOINT_NAME,\n\t\t},\n\t\tupstream: { type: 'container', containerName: containerNameFor(0), containerPort },\n\t\tcors: true,\n\t\twireProtocol: 'http',\n\t};\n\tconst publisher: RoutableDecl = {\n\t\tkind: 'routable',\n\t\tendpointName: WALRUS_PUBLISHER_ENDPOINT_NAME,\n\t\tdispatchId: {\n\t\t\tserviceKey: args.serviceKey,\n\t\t\trole: WALRUS_PUBLISHER_ENDPOINT_NAME,\n\t\t},\n\t\tupstream: { type: 'container', containerName: containerNameFor(0), containerPort },\n\t\tcors: true,\n\t\twireProtocol: 'http',\n\t};\n\n\treturn [...perNodeRoutes, aggregator, publisher];\n};\n"],"mappings":";;AAuBA,MAAa,8BAA8B;AAC3C,MAAa,kCAAkC;AAC/C,MAAa,iCAAiC;AAO9C,MAAa,qBAAoD;CAChE,GAAG,MAAM,KACR,EAAE,QAAA,EAA8B,IAC/B,GAAG,OAAuB;EAC1B,MAAM,GAAG,8BAA8B;EACvC,MAAM;EACN,UAAU;CACX,EACD;CACA;EAAE,MAAM;EAAiC,MAAM;EAAoB,UAAU;CAAO;CACpF;EAAE,MAAM;EAAgC,MAAM;EAAoB,UAAU;CAAO;AACpF;;;;AAKA,MAAa,sBAAsB,SAOA;CAClC,MAAM,gBAAgB,KAAK,oBAAA;CAC3B,MAAM,oBAAoB,MACzB,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,UAAU,KAAK,WAAW,QAAQ;CACtE,MAAM,gBAA6C,MAAM,KACxD,EAAE,QAAQ,KAAK,UAAU,IACxB,GAAG,OAAqB;EACxB,MAAM;EACN,cAAc,GAAG,8BAA8B;EAC/C,YAAY;GACX,YAAY,KAAK;GACjB,MAAM,GAAG,8BAA8B;EACxC;EACA,UAAU;GACT,MAAM;GACN,eAAe,iBAAiB,CAAC;GACjC;EACD;EAGA,MAAM;EACN,cAAc;CACf,EACD;CAMA,MAAM,aAA2B;EAChC,MAAM;EACN,cAAc;EACd,YAAY;GACX,YAAY,KAAK;GACjB,MAAM;EACP;EACA,UAAU;GAAE,MAAM;GAAa,eAAe,iBAAiB,CAAC;GAAG;EAAc;EACjF,MAAM;EACN,cAAc;CACf;CACA,MAAM,YAA0B;EAC/B,MAAM;EACN,cAAc;EACd,YAAY;GACX,YAAY,KAAK;GACjB,MAAM;EACP;EACA,UAAU;GAAE,MAAM;GAAa,eAAe,iBAAiB,CAAC;GAAG;EAAc;EACjF,MAAM;EACN,cAAc;CACf;CAEA,OAAO;EAAC,GAAG;EAAe;EAAY;CAAS;AAChD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.mjs","names":[],"sources":["../../../src/plugins/walrus/service.ts"],"sourcesContent":["// Walrus plugin — main acquire body. Mode dispatch.\n//\n// Distilled-doc reference (06-walrus.md §\"Modes & variants\" — four\n// distinct operating modes):\n//\n// - local — `walrusLocalCluster(...)`\n// - live (testnet/mainnet) — `walrusKnownDeployment(...)`\n// - fork-known (`*-fork`) — known-deployment wrapper for the\n// wrapped upstream\n// - fork-localcluster-refused — synchronous refusal at factory\n// time\n//\n// Architecture: Walrus is ONE plugin with internal mode dispatch.\n// The factory at the barrel (`index.ts`) constructs the discriminator\n// from typed options; this file dispatches on the discriminator and\n// assembles mode-appropriate\n// subsystems.\n//\n// What this file does:\n//\n// 1. Receive a resolved mode discriminator.\n// 2. Dispatch to the right `boot*` builder.\n// 3. Return the mode's boot artifacts (the barrel projects them\n// onto the plugin's resolved value).\n//\n// What it does NOT do:\n//\n// - Provision the container runtime — that arrives via the\n// `BuildContext` passed by the barrel.\n// - Resolve bootstrap assets — local-cluster mode owns those\n// resolvers; this file just dispatches.\n\nimport { Effect, FileSystem, Path, type Scope } from 'effect';\n\nimport type { ArtifactPublishError } from '../../primitives/artifact-publisher.ts';\nimport type { WalrusError } from './errors.ts';\nimport {\n\tbootKnownDeployment,\n\ttype KnownDeploymentBootResult,\n\ttype WalrusKnownDeploymentOptions,\n} from './mode/known-deploy.ts';\nimport {\n\tbootLocalCluster,\n\ttype LocalClusterBootResult,\n\ttype LocalClusterDeps,\n\ttype ResolvedLocalClusterOptions,\n} from './mode/local-cluster.ts';\n\n/** Mode discriminator. Internal — the barrel constructs ONE of these\n * per composed walrus instance and dispatches here. */\nexport type WalrusMode =\n\t| { readonly mode: 'local'; readonly opts: ResolvedLocalClusterOptions }\n\t| { readonly mode: 'known'; readonly opts: WalrusKnownDeploymentOptions };\n\n/** Result of one acquire — discriminated by mode so the barrel can\n * project mode-asymmetrically onto the tag set. */\nexport type WalrusBootResult = LocalClusterBootResult | KnownDeploymentBootResult;\n\n/** Dispatch on the mode and return the boot artifacts.\n *\n * `deps` is the local-cluster's full dependency bundle. The known\n * branch ignores all of it (no I/O at acquire time — purely\n * synchronous projection from options); the type lets the barrel\n * pass one record for both paths. */\nexport const bootWalrusService = (\n\tdeps: LocalClusterDeps,\n\tmode: WalrusMode,\n): Effect.Effect<\n\tWalrusBootResult,\n\tWalrusError | ArtifactPublishError,\n\tScope.Scope | FileSystem.FileSystem | Path.Path\n> => {\n\tswitch (mode.mode) {\n\t\tcase 'local':\n\t\t\treturn bootLocalCluster(deps, mode.opts);\n\t\tcase 'known':\n\t\t\treturn bootKnownDeployment(mode.opts);\n\t}\n};\n"],"mappings":";;;;;;;;;;AAgEA,MAAa,qBACZ,MACA,SAKI;
|
|
1
|
+
{"version":3,"file":"service.mjs","names":[],"sources":["../../../src/plugins/walrus/service.ts"],"sourcesContent":["// Walrus plugin — main acquire body. Mode dispatch.\n//\n// Distilled-doc reference (06-walrus.md §\"Modes & variants\" — four\n// distinct operating modes):\n//\n// - local — `walrusLocalCluster(...)`\n// - live (testnet/mainnet) — `walrusKnownDeployment(...)`\n// - fork-known (`*-fork`) — known-deployment wrapper for the\n// wrapped upstream\n// - fork-localcluster-refused — synchronous refusal at factory\n// time\n//\n// Architecture: Walrus is ONE plugin with internal mode dispatch.\n// The factory at the barrel (`index.ts`) constructs the discriminator\n// from typed options; this file dispatches on the discriminator and\n// assembles mode-appropriate\n// subsystems.\n//\n// What this file does:\n//\n// 1. Receive a resolved mode discriminator.\n// 2. Dispatch to the right `boot*` builder.\n// 3. Return the mode's boot artifacts (the barrel projects them\n// onto the plugin's resolved value).\n//\n// What it does NOT do:\n//\n// - Provision the container runtime — that arrives via the\n// `BuildContext` passed by the barrel.\n// - Resolve bootstrap assets — local-cluster mode owns those\n// resolvers; this file just dispatches.\n\nimport { Effect, FileSystem, Path, type Scope } from 'effect';\n\nimport type { ArtifactPublishError } from '../../primitives/artifact-publisher.ts';\nimport type { WalrusError } from './errors.ts';\nimport {\n\tbootKnownDeployment,\n\ttype KnownDeploymentBootResult,\n\ttype WalrusKnownDeploymentOptions,\n} from './mode/known-deploy.ts';\nimport {\n\tbootLocalCluster,\n\ttype LocalClusterBootResult,\n\ttype LocalClusterDeps,\n\ttype ResolvedLocalClusterOptions,\n} from './mode/local-cluster.ts';\n\n/** Mode discriminator. Internal — the barrel constructs ONE of these\n * per composed walrus instance and dispatches here. */\nexport type WalrusMode =\n\t| { readonly mode: 'local'; readonly opts: ResolvedLocalClusterOptions }\n\t| { readonly mode: 'known'; readonly opts: WalrusKnownDeploymentOptions };\n\n/** Result of one acquire — discriminated by mode so the barrel can\n * project mode-asymmetrically onto the tag set. */\nexport type WalrusBootResult = LocalClusterBootResult | KnownDeploymentBootResult;\n\n/** Dispatch on the mode and return the boot artifacts.\n *\n * `deps` is the local-cluster's full dependency bundle. The known\n * branch ignores all of it (no I/O at acquire time — purely\n * synchronous projection from options); the type lets the barrel\n * pass one record for both paths. */\nexport const bootWalrusService = (\n\tdeps: LocalClusterDeps,\n\tmode: WalrusMode,\n): Effect.Effect<\n\tWalrusBootResult,\n\tWalrusError | ArtifactPublishError,\n\tScope.Scope | FileSystem.FileSystem | Path.Path\n> => {\n\tswitch (mode.mode) {\n\t\tcase 'local':\n\t\t\treturn bootLocalCluster(deps, mode.opts);\n\t\tcase 'known':\n\t\t\treturn bootKnownDeployment(mode.opts);\n\t}\n};\n"],"mappings":";;;;;;;;;;AAgEA,MAAa,qBACZ,MACA,SAKI;CACJ,QAAQ,KAAK,MAAb;EACC,KAAK,SACJ,OAAO,iBAAiB,MAAM,KAAK,IAAI;EACxC,KAAK,SACJ,OAAO,oBAAoB,KAAK,IAAI;CACtC;AACD"}
|
|
@@ -9,7 +9,7 @@ import { Effect } from "effect";
|
|
|
9
9
|
* `nodeCount` (local mode only) drives the per-node managed-container
|
|
10
10
|
* decls. Each storage node carries `role: storage-node-${i}` so the
|
|
11
11
|
* substrate's label filter pauses/commits each independently. */
|
|
12
|
-
const makeSnapshotable = (mode, app, stack, walrusName,
|
|
12
|
+
const makeSnapshotable = (mode, app, stack, walrusName, network, nodeCount = 1) => {
|
|
13
13
|
const labels = (role) => ({
|
|
14
14
|
app,
|
|
15
15
|
stack,
|
|
@@ -29,7 +29,7 @@ const makeSnapshotable = (mode, app, stack, walrusName, chain, nodeCount = 1) =>
|
|
|
29
29
|
mode: "local",
|
|
30
30
|
name: walrusName,
|
|
31
31
|
nodeCount,
|
|
32
|
-
|
|
32
|
+
network
|
|
33
33
|
}),
|
|
34
34
|
postRestore: Effect.void,
|
|
35
35
|
secretMaterial: true
|
|
@@ -42,7 +42,7 @@ const makeSnapshotable = (mode, app, stack, walrusName, chain, nodeCount = 1) =>
|
|
|
42
42
|
preRestore: Effect.succeed({
|
|
43
43
|
kind: "walrus",
|
|
44
44
|
mode: "known",
|
|
45
|
-
|
|
45
|
+
network
|
|
46
46
|
})
|
|
47
47
|
};
|
|
48
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.mjs","names":[],"sources":["../../../src/plugins/walrus/snapshot.ts"],"sourcesContent":["// Walrus plugin — Snapshotable contribution.\n//\n// Distilled-doc reference (06-walrus.md §\"Persistence model\" +\n// §\"Hard requirements\" item 7):\n// - `runtime/walrus/<name>/deploy/` MUST ride the snapshot tar.\n// It holds storage-node private keys + per-node configs that\n// `walrus-deploy` wrote; without them, a
|
|
1
|
+
{"version":3,"file":"snapshot.mjs","names":[],"sources":["../../../src/plugins/walrus/snapshot.ts"],"sourcesContent":["// Walrus plugin — Snapshotable contribution.\n//\n// Distilled-doc reference (06-walrus.md §\"Persistence model\" +\n// §\"Hard requirements\" item 7):\n// - `runtime/walrus/<name>/deploy/` MUST ride the snapshot tar.\n// It holds storage-node private keys + per-node configs that\n// `walrus-deploy` wrote; without them, a cached \"walrus is already\n// deployed\" artifact cannot be honored on resume.\n// - Local cluster: N storage-node containers' writable layers\n// hold RocksDB at `/var/walrus/storage` — managed-containers\n// declaration; runtime adapter pauses then `docker commit`.\n// Per-node label tuple `role: storage-node-${i}` so the snapshot\n// orchestrator's label filter resolves each node distinctly.\n// - Known-deployment: no containers, no subtrees. The shape still\n// exists so the identity guard fires on restore.\n//\n// Identity guard: contributes the deploy mode + network + (when\n// local) the `name` discriminator to the pre-restore identity\n// record. A snapshot taken in local mode restored under known\n// mode (or vice versa) refuses BEFORE any destructive mutation.\n\nimport { Effect } from 'effect';\n\nimport type { ContainerLabelTuple, SnapshotableDecl } from '../../contracts/snapshotable.ts';\n\n/** Discriminator passed to `makeSnapshotable` — narrower than the\n * full mode union because the snapshot shape only cares about\n * \"local with containers\" vs \"known with nothing\". */\nexport type WalrusSnapshotMode = 'local' | 'known';\n\n/** Build the Snapshotable contribution.\n *\n * `app` / `stack` / `walrusName` are resolved at the plugin's\n * acquire-time so the snapshot's identity guard can match the\n * plugin's actual container labels.\n *\n * `nodeCount` (local mode only) drives the per-node managed-container\n * decls. Each storage node carries `role: storage-node-${i}` so the\n * substrate's label filter pauses/commits each independently. */\nexport const makeSnapshotable = (\n\tmode: WalrusSnapshotMode,\n\tapp: string,\n\tstack: string,\n\twalrusName: string,\n\tnetwork: string,\n\tnodeCount = 1,\n): SnapshotableDecl => {\n\tconst labels = (role: string): ContainerLabelTuple => ({\n\t\tapp,\n\t\tstack,\n\t\tplugin: 'walrus',\n\t\trole,\n\t});\n\n\tswitch (mode) {\n\t\tcase 'local': {\n\t\t\tconst perNodeContainers: ReadonlyArray<ContainerLabelTuple> = Array.from(\n\t\t\t\t{ length: nodeCount },\n\t\t\t\t(_, i) => labels(`storage-node-${i}`),\n\t\t\t);\n\t\t\treturn {\n\t\t\t\tkind: 'snapshotable',\n\t\t\t\t// `runtime/walrus/<name>/deploy/` — the deploy one-shot's\n\t\t\t\t// output dir. The substrate's runtime-dir root is\n\t\t\t\t// resolved at acquire; the path here is relative to it.\n\t\t\t\tsubtrees: [`walrus/${walrusName}/deploy/`],\n\t\t\t\tmanagedContainers: perNodeContainers,\n\t\t\t\tmissingTolerance: 'fine',\n\t\t\t\t// Storage nodes need >10s to flush + checkpoint RocksDB\n\t\t\t\t// on `docker stop`; the snapshot quiesce mirrors the\n\t\t\t\t// stop grace (distilled-doc invariant 22). Default\n\t\t\t\t// \"pause container\" gives us this for free in the\n\t\t\t\t// substrate's adapter.\n\t\t\t\tpreRestore: Effect.succeed({\n\t\t\t\t\tkind: 'walrus' as const,\n\t\t\t\t\tmode: 'local' as const,\n\t\t\t\t\tname: walrusName,\n\t\t\t\t\tnodeCount,\n\t\t\t\t\tnetwork,\n\t\t\t\t}),\n\t\t\t\tpostRestore: Effect.void,\n\t\t\t\t// Storage-node keystores are secret material; the\n\t\t\t\t// substrate preserves 0o600 on round-trip.\n\t\t\t\tsecretMaterial: true,\n\t\t\t};\n\t\t}\n\t\tcase 'known': {\n\t\t\treturn {\n\t\t\t\tkind: 'snapshotable',\n\t\t\t\tsubtrees: [],\n\t\t\t\tmissingTolerance: 'fine',\n\t\t\t\tpreRestore: Effect.succeed({\n\t\t\t\t\tkind: 'walrus' as const,\n\t\t\t\t\tmode: 'known' as const,\n\t\t\t\t\tnetwork,\n\t\t\t\t}),\n\t\t\t};\n\t\t}\n\t}\n};\n"],"mappings":";;;;;;;;;;;AAuCA,MAAa,oBACZ,MACA,KACA,OACA,YACA,SACA,YAAY,MACU;CACtB,MAAM,UAAU,UAAuC;EACtD;EACA;EACA,QAAQ;EACR;CACD;CAEA,QAAQ,MAAR;EACC,KAAK,SAAS;GACb,MAAM,oBAAwD,MAAM,KACnE,EAAE,QAAQ,UAAU,IACnB,GAAG,MAAM,OAAO,gBAAgB,GAAG,CACrC;GACA,OAAO;IACN,MAAM;IAIN,UAAU,CAAC,UAAU,WAAW,SAAS;IACzC,mBAAmB;IACnB,kBAAkB;IAMlB,YAAY,OAAO,QAAQ;KAC1B,MAAM;KACN,MAAM;KACN,MAAM;KACN;KACA;IACD,CAAC;IACD,aAAa,OAAO;IAGpB,gBAAgB;GACjB;EACD;EACA,KAAK,SACJ,OAAO;GACN,MAAM;GACN,UAAU,CAAC;GACX,kBAAkB;GAClB,YAAY,OAAO,QAAQ;IAC1B,MAAM;IACN,MAAM;IACN;GACD,CAAC;EACF;CAEF;AACD"}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { SpanAttr } from "../../substrate/runtime/observability/spans.mjs";
|
|
2
|
-
import { ProbeTimeoutError, exitCodeProbeResult, waitForProbe } from "../../substrate/runtime/probes.mjs";
|
|
3
1
|
import { setCurrentPluginPhase } from "../../substrate/runtime/current-plugin.mjs";
|
|
2
|
+
import { ProbeTimeoutError, exitCodeProbeResult, waitForProbe } from "../../substrate/runtime/probes.mjs";
|
|
4
3
|
import { HOST_GATEWAY_EXTRA_HOSTS } from "../../substrate/runtime/host-gateway.mjs";
|
|
5
4
|
import { ensureManagedContainer } from "../../substrate/runtime/managed-container.mjs";
|
|
6
5
|
import { walrusDeployMountPaths } from "./deploy-paths.mjs";
|
|
7
6
|
import { walrusPluginError } from "./errors.mjs";
|
|
8
|
-
import { WalrusSpans } from "./spans.mjs";
|
|
9
7
|
import { Duration, Effect, Scope } from "effect";
|
|
10
8
|
/** Default per-node ready-probe timeout. */
|
|
11
9
|
const DEFAULT_NODE_READY_TIMEOUT_MS = 6e4;
|
|
@@ -18,8 +16,8 @@ const WALRUS_ROUTER_PORT = 9185;
|
|
|
18
16
|
* the container. Same value as the router port (the storage node's
|
|
19
17
|
* in-container bind matches the on-chain public_port). */
|
|
20
18
|
const DEFAULT_CONTAINER_API_PORT = WALRUS_ROUTER_PORT;
|
|
21
|
-
/** Compute the public hostname for one storage node
|
|
22
|
-
*
|
|
19
|
+
/** Compute the public hostname for one storage node — the
|
|
20
|
+
* `routerHostname(identity, 'walrus-node-' + i)` shape
|
|
23
21
|
* (06-walrus.md §"Routes registered"). Main stack omits the stack
|
|
24
22
|
* segment; non-main inserts it after the service label. */
|
|
25
23
|
const computePublicHostname = (app, stack, nodeIndex) => {
|
|
@@ -36,6 +34,40 @@ const storageNodeConfigHash = (parts) => [
|
|
|
36
34
|
const buildWalrusNetworkName = (app, stack, walrusName) => `devstack-${app}-${stack}-walrus-${walrusName}-net`;
|
|
37
35
|
/** Per-node TCP ready-probe interval. */
|
|
38
36
|
const NODE_READY_PROBE_INTERVAL_MS = 500;
|
|
37
|
+
/** Walrus storage-node REST health endpoint (TLS disabled — plain HTTP
|
|
38
|
+
* behind the router; see images/walrus/deploy-walrus.sh which rebinds
|
|
39
|
+
* `rest_api_address` on 0.0.0.0 and sets `disable_tls: true`). The node
|
|
40
|
+
* serves `GET /v1/health` once its API listener binds; the JSON body's
|
|
41
|
+
* `nodeStatus` field reports the committee-sync state. */
|
|
42
|
+
const NODE_HEALTH_PATH = "/v1/health";
|
|
43
|
+
/** Recovery / not-yet-serving markers in a `/v1/health` body. A node that
|
|
44
|
+
* just recreated (fresh `docker run` from a committed/restored image — the
|
|
45
|
+
* snapshot capture/restore resume) comes back up and reports a recovery
|
|
46
|
+
* status while it re-syncs its committee/epoch; writing a blob to it before
|
|
47
|
+
* it catches up fails the write quorum with "Too many failures while
|
|
48
|
+
* writing blob to nodes". The boot ready-gate blocks until NONE of these
|
|
49
|
+
* markers is present so the node is genuinely serving. */
|
|
50
|
+
const NODE_RECOVERY_MARKERS = [
|
|
51
|
+
/"nodeStatus"\s*:\s*"Recovery/i,
|
|
52
|
+
/"nodeStatus"\s*:\s*"Standby"/i,
|
|
53
|
+
/"nodeStatus"\s*:\s*"Starting"/i,
|
|
54
|
+
/"isInRecovery"\s*:\s*true/i,
|
|
55
|
+
/"inRecovery"\s*:\s*true/i
|
|
56
|
+
];
|
|
57
|
+
/** Classify a `/v1/health` 2xx body as write-ready. Biased toward NOT
|
|
58
|
+
* false-negativing the boot (a too-strict classifier would time the boot
|
|
59
|
+
* out on a field-name change upstream): a node whose health endpoint
|
|
60
|
+
* returns 2xx is treated as serving UNLESS the body explicitly reports a
|
|
61
|
+
* recovery / standby / starting status. The explicit `Active` serving
|
|
62
|
+
* status is the fast-path. This gates EVERY acquire path (up / restart /
|
|
63
|
+
* restore-converge / capture-resume) on write-readiness, not just
|
|
64
|
+
* process-up — the snapshot survival-matrix fix. */
|
|
65
|
+
const isWriteReadyHealthBody = (body) => {
|
|
66
|
+
const trimmed = body.trim();
|
|
67
|
+
if (/"nodeStatus"\s*:\s*"Active"/i.test(trimmed)) return true;
|
|
68
|
+
if (trimmed.length === 0) return false;
|
|
69
|
+
return !NODE_RECOVERY_MARKERS.some((marker) => marker.test(trimmed));
|
|
70
|
+
};
|
|
39
71
|
/** Start the N-node committee.
|
|
40
72
|
*
|
|
41
73
|
* Wiring (this body is the load-bearing path):
|
|
@@ -129,7 +161,7 @@ const startStorageNodes = (runtime, spec) => Effect.gen(function* () {
|
|
|
129
161
|
mapError: (cause) => walrusPluginError("storage-node", `walrus storage-node-${i} (ip=${containerIp}) ensureContainer failed: ${cause.reason}: ${cause.detail}`, { cause })
|
|
130
162
|
});
|
|
131
163
|
const handle = yield* Scope.provide(ensureNode, nodeStopScope);
|
|
132
|
-
yield* setCurrentPluginPhase(`waiting for storage-node-${i} on 127.0.0.1:${spec.containerApiPort}`);
|
|
164
|
+
yield* setCurrentPluginPhase(`waiting for storage-node-${i} write-readiness on 127.0.0.1:${spec.containerApiPort}`);
|
|
133
165
|
yield* waitForProbe({
|
|
134
166
|
label: `walrus.storage-node.${i}`,
|
|
135
167
|
timeoutMs: Duration.toMillis(readyTimeout),
|
|
@@ -137,10 +169,20 @@ const startStorageNodes = (runtime, spec) => Effect.gen(function* () {
|
|
|
137
169
|
probe: () => runtime.exec(handle, [
|
|
138
170
|
"sh",
|
|
139
171
|
"-c",
|
|
140
|
-
`nc -z 127.0.0.1 ${spec.containerApiPort} || exit 1`
|
|
141
|
-
]).pipe(Effect.map(
|
|
172
|
+
`nc -z 127.0.0.1 ${spec.containerApiPort} || exit 1; curl -fs http://127.0.0.1:${spec.containerApiPort}${NODE_HEALTH_PATH} || exit 1`
|
|
173
|
+
]).pipe(Effect.map((result) => {
|
|
174
|
+
if (result.exitCode !== 0) return exitCodeProbeResult(result);
|
|
175
|
+
if (isWriteReadyHealthBody(result.stdout)) return true;
|
|
176
|
+
return {
|
|
177
|
+
ready: false,
|
|
178
|
+
detail: {
|
|
179
|
+
nodeStatus: "not-serving",
|
|
180
|
+
body: result.stdout.slice(0, 256)
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}))
|
|
142
184
|
}).pipe(Effect.mapError((cause) => {
|
|
143
|
-
if (cause instanceof ProbeTimeoutError) return walrusPluginError("storage-node", `storage-node-${i} never became ready within ${Duration.toMillis(readyTimeout)}ms (container=${containerName}, probe=127.0.0.1:${spec.containerApiPort}, publicUrl=http://${publicHostname}:${WALRUS_ROUTER_PORT}). The container was created, but walrus-node did not bind its API port. Check the storage-node container logs for the faucet, WAL exchange, or walrus-node run step that stalled.`, { cause: cause.lastError ?? cause.lastNotReady ?? cause });
|
|
185
|
+
if (cause instanceof ProbeTimeoutError) return walrusPluginError("storage-node", `storage-node-${i} never became write-ready within ${Duration.toMillis(readyTimeout)}ms (container=${containerName}, probe=127.0.0.1:${spec.containerApiPort}${NODE_HEALTH_PATH}, publicUrl=http://${publicHostname}:${WALRUS_ROUTER_PORT}). The container was created, but walrus-node did not bind its API port or did not finish re-syncing its committee/epoch to a serving nodeStatus (a node recreated from a committed/restored snapshot image must catch up before it accepts blob writes). Check the storage-node container logs for the faucet, WAL exchange, committee recovery, or walrus-node run step that stalled.`, { cause: cause.lastError ?? cause.lastNotReady ?? cause });
|
|
144
186
|
return walrusPluginError("storage-node", `storage-node-${i} ready-probe exec failed: ${cause.reason}: ${cause.detail}`, { cause });
|
|
145
187
|
}));
|
|
146
188
|
return {
|
|
@@ -149,12 +191,9 @@ const startStorageNodes = (runtime, spec) => Effect.gen(function* () {
|
|
|
149
191
|
publicHostname,
|
|
150
192
|
rpcUrl: `http://${publicHostname}:${WALRUS_ROUTER_PORT}`
|
|
151
193
|
};
|
|
152
|
-
})
|
|
153
|
-
[SpanAttr.plugin]: "walrus",
|
|
154
|
-
[WalrusSpans.node]: i
|
|
155
|
-
} }));
|
|
194
|
+
});
|
|
156
195
|
return { nodes: yield* Effect.all(indices.map(bootOne), { concurrency: "unbounded" }) };
|
|
157
|
-
})
|
|
196
|
+
});
|
|
158
197
|
//#endregion
|
|
159
198
|
export { DEFAULT_CONTAINER_API_PORT, DEFAULT_NODE_READY_TIMEOUT_MS, WALRUS_ROUTER_PORT, buildWalrusNetworkName, computePublicHostname, startStorageNodes };
|
|
160
199
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-nodes.mjs","names":[],"sources":["../../../src/plugins/walrus/storage-nodes.ts"],"sourcesContent":["// Walrus storage-node committee lifecycle.\n//\n// Distilled-doc reference (06-walrus.md §\"Capabilities CONSUMED\" +\n// §\"Lifecycle phase 4\"): N storage-node containers, pinned IPs on a\n// per-stack /24 docker network. Each node carries one Traefik route\n// via the `Routable` capability; the router binds host port 9185 once\n// globally and dispatches by `Host:` header.\n//\n// Substrate-side responsibilities:\n// - `ContainerRuntime.ensureContainer` per node — content-addressed\n// image, label tuple, recreate policy.\n// - Parallel `Effect.all({concurrency: 'unbounded'})` over [0..N) —\n// concurrent boot.\n// - Per-node stop finalizer fires in a *forked parallel scope* so\n// teardown collapses to ~max(grace) instead of summing graces\n// (distilled-doc invariant 21 — \"StopFinalizerScope MUST be a\n// forked parallel scope\").\n//\n// What we DON'T own here:\n// - Plugin row narration.\n// - The faucet-strategy registration — `faucet-strategy.ts`.\n// - The deploy one-shot — `deploy.ts`.\n\nimport { Duration, Effect, Scope } from 'effect';\n\nimport type {\n\tContainerHandle,\n\tContainerRuntime,\n\tImageRef,\n} from '../../contracts/container-runtime.ts';\nimport {\n\tProbeTimeoutError,\n\texitCodeProbeResult,\n\twaitForProbe,\n} from '../../substrate/runtime/probes.ts';\nimport { setCurrentPluginPhase } from '../../substrate/runtime/current-plugin.ts';\nimport { ensureManagedContainer } from '../../substrate/runtime/managed-container.ts';\nimport { HOST_GATEWAY_EXTRA_HOSTS } from '../../substrate/runtime/host-gateway.ts';\nimport { SpanAttr } from '../../substrate/runtime/observability/spans.ts';\nimport { walrusDeployMountPaths } from './deploy-paths.ts';\nimport { walrusPluginError, type WalrusPluginError } from './errors.ts';\nimport { WalrusSpans } from './spans.ts';\n\n/** Default per-node grace window. Storage nodes maintain RocksDB-\n * backed state; need >10s to flush and checkpoint on `docker stop`.\n * Distilled-doc invariant 22. */\nexport const DEFAULT_NODE_STOP_GRACE_SECONDS = 20;\n\n/** Default per-node ready-probe timeout. */\nexport const DEFAULT_NODE_READY_TIMEOUT_MS = 60_000;\n\n/** Distilled-doc invariant 9: the on-chain `public_port` value\n * matches the global router entrypoint port. One canonical\n * constant — opportunity #14 in the distilled doc was to deduplicate\n * this across three files. */\nexport const WALRUS_ROUTER_PORT = 9185;\n\n/** Default container API port — each storage node binds this inside\n * the container. Same value as the router port (the storage node's\n * in-container bind matches the on-chain public_port). */\nexport const DEFAULT_CONTAINER_API_PORT = WALRUS_ROUTER_PORT;\n\n/** Per-node descriptor — what the plugin resolved value surfaces\n * for downstream consumers (the `@mysten/walrus` SDK reads this).\n *\n * Note: no `publicKey` field. The per-node BLS12-381 keypair lives\n * inside the per-node keystore the deploy one-shot emitted; the SDK\n * consumer reads the public key off `packageConfig` rather than this\n * routing-handle descriptor. */\nexport interface WalrusStorageNode {\n\treadonly nodeIndex: number;\n\treadonly nodeId: string;\n\treadonly publicHostname: string;\n\treadonly rpcUrl: string;\n}\n\n/** Storage-node startup config — the plugin's local-cluster mode\n * passes this in once per cluster boot. */\nexport interface StorageNodesSpec {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly walrusName: string;\n\t/** One image ref PER node (`images[i]` for node `i`; length MUST equal\n\t * `nodeCount`). Each node runs under its own tag so its committed writable\n\t * layer (RocksDB slivers) promotes to a DISTINCT image on snapshot restore;\n\t * a single shared tag collapses N committed layers -> 1 on the restore\n\t * image-promote, orphaning N-1 nodes' blobs. */\n\treadonly images: ReadonlyArray<ImageRef>;\n\treadonly nodeCount: number;\n\t/** Pre-allocated /24 prefix from `subnetForStack`. Example:\n\t * `'10.42.7'` (the third octet is hashed per stack). */\n\treadonly subnetPrefix: string;\n\treadonly containerApiPort: number;\n\treadonly walrusNetworkName: string;\n\treadonly suiNetworkName: string;\n\treadonly deployHostMountPath: string;\n\t/** On-disk per-stack root from `StackPathsService.stackRoot`. The\n\t * walrus bind-mount is computed by `walrusDeployMountPaths` as\n\t * `<stackRoot> -> <mountTarget>`; the deploy output dir MUST be a\n\t * descendant. Threaded explicitly to remove the previous\n\t * `dirname(dirname(dirname(...)))` walk-up footgun. */\n\treadonly stackRoot: string;\n\t/** Fingerprint of the deploy outputs mounted into each node. */\n\treadonly deployConfigHash: string;\n\treadonly stopGraceSeconds?: number;\n\treadonly readyTimeoutMs?: number;\n}\n\n/** Result of starting the committee — descriptors used by the\n * plugin's resolved value. */\nexport interface StorageNodesAcquired {\n\treadonly nodes: ReadonlyArray<WalrusStorageNode>;\n}\n\n/** Distilled-doc invariant 1: pinned IPs start at `<prefix>.10`.\n * Centralized so the deploy one-shot's `WALRUS_LISTENING_IPS` env\n * var and the per-node `--ip` pin compute from one source. */\nexport const WALRUS_NODE_IP_BASE = 10;\n\n/** Compute the public hostname for one storage node. Mirrors\n * v3's `routerHostname(identity, 'walrus-node-' + i)` shape\n * (06-walrus.md §\"Routes registered\"). Main stack omits the stack\n * segment; non-main inserts it after the service label. */\nexport const computePublicHostname = (app: string, stack: string, nodeIndex: number): string => {\n\tconst base = `walrus-node-${nodeIndex}.${app}.localhost`;\n\treturn stack === 'main' ? base : `walrus-node-${nodeIndex}.${stack}.${app}.localhost`;\n};\n\nexport const storageNodeConfigHash = (parts: {\n\treadonly deployConfigHash: string;\n\treadonly nodeIndex: number;\n\treadonly deploySourceHostPath: string;\n\treadonly deployMountTarget: string;\n\treadonly containerApiPort: number;\n\treadonly walrusNetworkName: string;\n\treadonly suiNetworkName: string;\n}): string =>\n\t[\n\t\tparts.deployConfigHash,\n\t\t`node=${parts.nodeIndex}`,\n\t\t`mount=${parts.deploySourceHostPath}->${parts.deployMountTarget}`,\n\t\t`api=${parts.containerApiPort}`,\n\t\t`net=${parts.walrusNetworkName},${parts.suiNetworkName}`,\n\t].join('|');\n\nexport const buildWalrusNetworkName = (app: string, stack: string, walrusName: string): string =>\n\t`devstack-${app}-${stack}-walrus-${walrusName}-net`;\n\n/** Per-node TCP ready-probe interval. */\nconst NODE_READY_PROBE_INTERVAL_MS = 500;\n\n/** Start the N-node committee.\n *\n * Wiring (this body is the load-bearing path):\n *\n * 1. Defense-in-depth nodeCount guard.\n * 2. Fork a parallel-strategy child scope off the caller's scope so\n * every node's `docker stop` finalizer fires concurrently on\n * outer teardown — collapses shutdown wall-time from `N×grace` to\n * `~max(grace)` (distilled-doc invariant 21).\n * 3. For each `i ∈ [0..N)`:\n * a. `ensureContainer` on the wrapper image with pinned IP,\n * label tuple, primary network attach (walrus net), recreate\n * on config-change.\n * b. TCP ready probe against `<publicHostname>:<routerPort>`\n * with bounded retries until the outer `readyTimeoutMs`.\n * 4. Run [3] under `Effect.all({concurrency: 'unbounded'})` — boot\n * parallelism collapses to ~max(perNode).\n *\n * WHAT THE SUBSTRATE STILL OWES:\n * - Secondary network attach (`Docker.networkConnect(suiNet)`).\n * `EnsureContainerSpec.networkAttach` accepts an array, so passing\n * `[walrusNet, suiNet]` would dual-home in one shot, but the\n * runtime adapter currently treats the first entry as the primary\n * and post-attaches the rest; the per-node pinned IP only attaches\n * to the primary. The dual-home is documented inline below and\n * relies on that adapter behavior. Storage nodes do not request\n * faucet funds during boot; the secondary network is retained for\n * future Sui-side in-network calls.\n * - Per-node `networkAlias` (`walrus-node-<i>.localhost`). The\n * contract doesn't expose alias plumbing yet; peer containers dial by\n * container name, which docker DNS publishes. The architecture\n * revision is tracked in `index.ts`.\n * - Stop-grace duration propagation. The contract's `stop` takes a\n * Duration but `ensureContainer` doesn't yet accept a default\n * grace; the runtime adapter defaults to 10s. RocksDB needs 20s\n * (distilled-doc invariant 22) — see opportunity below.\n */\nexport const startStorageNodes = (\n\truntime: ContainerRuntime,\n\tspec: StorageNodesSpec,\n): Effect.Effect<StorageNodesAcquired, WalrusPluginError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tif (spec.nodeCount < 1) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'storage-node',\n\t\t\t\t\t`storage-nodes: nodeCount must be >= 1 (got ${spec.nodeCount})`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (spec.images.length !== spec.nodeCount) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'storage-node',\n\t\t\t\t\t`storage-nodes: images length (${spec.images.length}) must equal nodeCount (${spec.nodeCount}) — one distinct per-node image tag is required for restore-safe commits`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// Fork a parallel stop-scope. Per-node `ensureContainer` finalizers\n\t\t// fire here on outer teardown; closing the parallel scope races\n\t\t// the per-container `docker stop`s instead of summing them.\n\t\t//\n\t\t// Cascade semantics (verified against effect-v4 `Scope.ts`\n\t\t// `fork` docs — \"Closing the parent closes the child with the\n\t\t// same exit value\"): when ANY `bootOne` fails (e.g. a ready-\n\t\t// probe times out on node i), `Effect.all` interrupts the rest;\n\t\t// the failure propagates up through the encompassing\n\t\t// `Effect.scoped` boundary which closes `outerScope`; that\n\t\t// cascade-closes `nodeStopScope`, running EVERY already-acquired\n\t\t// per-node `docker stop` finalizer in parallel. The probe is\n\t\t// intentionally OUTSIDE `Scope.provide(nodeStopScope)` — its\n\t\t// failures do NOT need their own finalizer attached to the\n\t\t// stop scope; the just-started container's finalizer is already\n\t\t// there from the `ensureNode` acquire that preceded the probe.\n\t\tconst outerScope = yield* Effect.scope;\n\t\tconst nodeStopScope = yield* Scope.fork(outerScope, 'parallel');\n\n\t\tconst stopGraceSeconds = spec.stopGraceSeconds ?? DEFAULT_NODE_STOP_GRACE_SECONDS;\n\t\tconst readyTimeout = Duration.millis(spec.readyTimeoutMs ?? DEFAULT_NODE_READY_TIMEOUT_MS);\n\t\tconst deployMount = walrusDeployMountPaths({\n\t\t\tstackRoot: spec.stackRoot,\n\t\t\tdeployOutputDirHostPath: spec.deployHostMountPath,\n\t\t\tmountTarget: '/opt/walrus/runtime',\n\t\t});\n\n\t\tconst indices = Array.from({ length: spec.nodeCount }, (_, i) => i);\n\n\t\tconst bootOne = (i: number): Effect.Effect<WalrusStorageNode, WalrusPluginError, Scope.Scope> =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst containerIp = `${spec.subnetPrefix}.${WALRUS_NODE_IP_BASE + i}`;\n\t\t\t\tconst containerName = `devstack-${spec.app}-${spec.stack}-walrus-${spec.walrusName}-node-${i}`;\n\t\t\t\tconst nodeHostname = `dryrun-node-${i}`;\n\t\t\t\tconst publicHostname = computePublicHostname(spec.app, spec.stack, i);\n\n\t\t\t\tyield* setCurrentPluginPhase(`creating storage-node-${i} container ${containerName}`);\n\t\t\t\t// Acquire under the forked parallel stop scope so the\n\t\t\t\t// finalizer (docker stop) joins the per-node fan-out race.\n\t\t\t\tconst ensureNode: Effect.Effect<ContainerHandle, WalrusPluginError, Scope.Scope> =\n\t\t\t\t\tensureManagedContainer<WalrusPluginError>({\n\t\t\t\t\t\truntime,\n\t\t\t\t\t\tidentity: { app: spec.app, stack: spec.stack },\n\t\t\t\t\t\tplugin: 'walrus',\n\t\t\t\t\t\trole: `storage-node-${i}`,\n\t\t\t\t\t\tspec: {\n\t\t\t\t\t\t\tname: containerName,\n\t\t\t\t\t\t\t// Node `i`'s own image tag — distinct per node so its\n\t\t\t\t\t\t\t// committed RocksDB layer survives snapshot restore.\n\t\t\t\t\t\t\timage: spec.images[i]!,\n\t\t\t\t\t\t\trecreate: 'on-config-change',\n\t\t\t\t\t\t\tconfigHash: storageNodeConfigHash({\n\t\t\t\t\t\t\t\tdeployConfigHash: spec.deployConfigHash,\n\t\t\t\t\t\t\t\tnodeIndex: i,\n\t\t\t\t\t\t\t\tdeploySourceHostPath: deployMount.sourceHostPath,\n\t\t\t\t\t\t\t\tdeployMountTarget: deployMount.mountTarget,\n\t\t\t\t\t\t\t\tcontainerApiPort: spec.containerApiPort,\n\t\t\t\t\t\t\t\twalrusNetworkName: spec.walrusNetworkName,\n\t\t\t\t\t\t\t\tsuiNetworkName: spec.suiNetworkName,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\t\tHOSTNAME: nodeHostname,\n\t\t\t\t\t\t\t\tDEPLOY_OUTPUT_DIR: deployMount.outputDirInContainer,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tstopGraceSeconds,\n\t\t\t\t\t\t\t// Primary network owns the pinned `--ip`; the\n\t\t\t\t\t\t\t// secondary attach gives docker DNS for the sui\n\t\t\t\t\t\t\t// network. The adapter treats [0] as primary.\n\t\t\t\t\t\t\tnetworkAttach: [spec.walrusNetworkName, spec.suiNetworkName],\n\t\t\t\t\t\t\t// Storage nodes dial sui's host-bound RPC + faucet via\n\t\t\t\t\t\t\t// `host.docker.internal`. See\n\t\t\t\t\t\t\t// substrate/runtime/host-gateway.ts for the platform\n\t\t\t\t\t\t\t// rationale (Docker Desktop auto-wires; native Linux\n\t\t\t\t\t\t\t// Docker requires the explicit `--add-host`).\n\t\t\t\t\t\t\textraHosts: HOST_GATEWAY_EXTRA_HOSTS,\n\t\t\t\t\t\t\tmounts: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Mount the stack root and point the entrypoint at\n\t\t\t\t\t\t\t\t\t// the deploy child. Docker Desktop can reject\n\t\t\t\t\t\t\t\t\t// freshly-created nested bind sources immediately\n\t\t\t\t\t\t\t\t\t// after a wiped stack recreates them.\n\t\t\t\t\t\t\t\t\tsource: deployMount.sourceHostPath,\n\t\t\t\t\t\t\t\t\ttarget: deployMount.mountTarget,\n\t\t\t\t\t\t\t\t\treadonly: true,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmapError: (cause) =>\n\t\t\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t\t\t'storage-node',\n\t\t\t\t\t\t\t\t`walrus storage-node-${i} (ip=${containerIp}) ensureContainer failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t\t\t{ cause },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t});\n\t\t\t\tconst handle: ContainerHandle = yield* Scope.provide(ensureNode, nodeStopScope);\n\n\t\t\t\t// TCP ready probe. We exec a tiny `nc`-style probe inside\n\t\t\t\t// the container against its own listener — proves the\n\t\t\t\t// in-container HTTP server bound and is accepting before\n\t\t\t\t// declaring ready. `exec` only fails on daemon-level\n\t\t\t\t// errors; a non-zero exit code is treated as \"retry\"\n\t\t\t\t// (the same policy postgres uses for `pg_isready`).\n\t\t\t\tyield* setCurrentPluginPhase(\n\t\t\t\t\t`waiting for storage-node-${i} on 127.0.0.1:${spec.containerApiPort}`,\n\t\t\t\t);\n\t\t\t\tyield* waitForProbe({\n\t\t\t\t\tlabel: `walrus.storage-node.${i}`,\n\t\t\t\t\ttimeoutMs: Duration.toMillis(readyTimeout),\n\t\t\t\t\tintervalMs: NODE_READY_PROBE_INTERVAL_MS,\n\t\t\t\t\tprobe: () =>\n\t\t\t\t\t\truntime\n\t\t\t\t\t\t\t.exec(handle, [\n\t\t\t\t\t\t\t\t'sh',\n\t\t\t\t\t\t\t\t'-c',\n\t\t\t\t\t\t\t\t// busybox-style portable probe: open TCP, write\n\t\t\t\t\t\t\t\t// nothing, exit. `nc -z` is the common form.\n\t\t\t\t\t\t\t\t`nc -z 127.0.0.1 ${spec.containerApiPort} || exit 1`,\n\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t.pipe(Effect.map(exitCodeProbeResult)),\n\t\t\t\t}).pipe(\n\t\t\t\t\tEffect.mapError((cause) => {\n\t\t\t\t\t\tif (cause instanceof ProbeTimeoutError) {\n\t\t\t\t\t\t\treturn walrusPluginError(\n\t\t\t\t\t\t\t\t'storage-node',\n\t\t\t\t\t\t\t\t`storage-node-${i} never became ready within ${Duration.toMillis(readyTimeout)}ms ` +\n\t\t\t\t\t\t\t\t\t`(container=${containerName}, probe=127.0.0.1:${spec.containerApiPort}, ` +\n\t\t\t\t\t\t\t\t\t`publicUrl=http://${publicHostname}:${WALRUS_ROUTER_PORT}). ` +\n\t\t\t\t\t\t\t\t\t`The container was created, but walrus-node did not bind its API port. ` +\n\t\t\t\t\t\t\t\t\t`Check the storage-node container logs for the faucet, WAL exchange, or ` +\n\t\t\t\t\t\t\t\t\t`walrus-node run step that stalled.`,\n\t\t\t\t\t\t\t\t{ cause: cause.lastError ?? cause.lastNotReady ?? cause },\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn walrusPluginError(\n\t\t\t\t\t\t\t'storage-node',\n\t\t\t\t\t\t\t`storage-node-${i} ready-probe exec failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t\t{ cause },\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn {\n\t\t\t\t\tnodeIndex: i,\n\t\t\t\t\t// Stable node-id derived from name. The on-chain\n\t\t\t\t\t// public_key + bls12-381 keypair lives inside the\n\t\t\t\t\t// per-node keystore the deploy one-shot emitted;\n\t\t\t\t\t// this descriptor is the routing handle, not the\n\t\t\t\t\t// crypto identity. The SDK consumer reads the\n\t\t\t\t\t// public key off `packageConfig` rather than this\n\t\t\t\t\t// per-node descriptor.\n\t\t\t\t\tnodeId: `walrus-node-${i}`,\n\t\t\t\t\tpublicHostname,\n\t\t\t\t\t// Router-fronted URL on the well-known walrus\n\t\t\t\t\t// entrypoint port — Traefik routes by Host: header.\n\t\t\t\t\trpcUrl: `http://${publicHostname}:${WALRUS_ROUTER_PORT}`,\n\t\t\t\t} satisfies WalrusStorageNode;\n\t\t\t}).pipe(\n\t\t\t\tEffect.withSpan(`devstack.plugin.walrus.storage-node-${i}.boot`, {\n\t\t\t\t\tattributes: { [SpanAttr.plugin]: 'walrus', [WalrusSpans.node]: i },\n\t\t\t\t}),\n\t\t\t);\n\n\t\tconst nodes = yield* Effect.all(indices.map(bootOne), {\n\t\t\tconcurrency: 'unbounded',\n\t\t});\n\n\t\treturn { nodes };\n\t}).pipe(\n\t\tEffect.withSpan('devstack.plugin.walrus.storage-nodes.boot', {\n\t\t\tattributes: { [SpanAttr.plugin]: 'walrus' },\n\t\t}),\n\t);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"storage-nodes.mjs","names":[],"sources":["../../../src/plugins/walrus/storage-nodes.ts"],"sourcesContent":["// Walrus storage-node committee lifecycle.\n//\n// Distilled-doc reference (06-walrus.md §\"Capabilities CONSUMED\" +\n// §\"Lifecycle phase 4\"): N storage-node containers, pinned IPs on a\n// per-stack /24 docker network. Each node carries one Traefik route\n// via the `Routable` capability; the router binds host port 9185 once\n// globally and dispatches by `Host:` header.\n//\n// Substrate-side responsibilities:\n// - `ContainerRuntime.ensureContainer` per node — content-addressed\n// image, label tuple, recreate policy.\n// - Parallel `Effect.all({concurrency: 'unbounded'})` over [0..N) —\n// concurrent boot.\n// - Per-node stop finalizer fires in a *forked parallel scope* so\n// teardown collapses to ~max(grace) instead of summing graces\n// (distilled-doc invariant 21 — \"StopFinalizerScope MUST be a\n// forked parallel scope\").\n//\n// What we DON'T own here:\n// - Plugin row narration.\n// - The faucet-strategy registration — `faucet-strategy.ts`.\n// - The deploy one-shot — `deploy.ts`.\n\nimport { Duration, Effect, Scope } from 'effect';\n\nimport type {\n\tContainerHandle,\n\tContainerRuntime,\n\tImageRef,\n} from '../../contracts/container-runtime.ts';\nimport {\n\tProbeTimeoutError,\n\texitCodeProbeResult,\n\twaitForProbe,\n} from '../../substrate/runtime/probes.ts';\nimport { setCurrentPluginPhase } from '../../substrate/runtime/current-plugin.ts';\nimport { ensureManagedContainer } from '../../substrate/runtime/managed-container.ts';\nimport { HOST_GATEWAY_EXTRA_HOSTS } from '../../substrate/runtime/host-gateway.ts';\nimport { walrusDeployMountPaths } from './deploy-paths.ts';\nimport { walrusPluginError, type WalrusPluginError } from './errors.ts';\n\n/** Default per-node grace window. Storage nodes maintain RocksDB-\n * backed state; need >10s to flush and checkpoint on `docker stop`.\n * Distilled-doc invariant 22. */\nexport const DEFAULT_NODE_STOP_GRACE_SECONDS = 20;\n\n/** Default per-node ready-probe timeout. */\nexport const DEFAULT_NODE_READY_TIMEOUT_MS = 60_000;\n\n/** Distilled-doc invariant 9: the on-chain `public_port` value\n * matches the global router entrypoint port. One canonical\n * constant — opportunity #14 in the distilled doc was to deduplicate\n * this across three files. */\nexport const WALRUS_ROUTER_PORT = 9185;\n\n/** Default container API port — each storage node binds this inside\n * the container. Same value as the router port (the storage node's\n * in-container bind matches the on-chain public_port). */\nexport const DEFAULT_CONTAINER_API_PORT = WALRUS_ROUTER_PORT;\n\n/** Per-node descriptor — what the plugin resolved value surfaces\n * for downstream consumers (the `@mysten/walrus` SDK reads this).\n *\n * Note: no `publicKey` field. The per-node BLS12-381 keypair lives\n * inside the per-node keystore the deploy one-shot emitted; the SDK\n * consumer reads the public key off `packageConfig` rather than this\n * routing-handle descriptor. */\nexport interface WalrusStorageNode {\n\treadonly nodeIndex: number;\n\treadonly nodeId: string;\n\treadonly publicHostname: string;\n\treadonly rpcUrl: string;\n}\n\n/** Storage-node startup config — the plugin's local-cluster mode\n * passes this in once per cluster boot. */\nexport interface StorageNodesSpec {\n\treadonly app: string;\n\treadonly stack: string;\n\treadonly walrusName: string;\n\t/** One image ref PER node (`images[i]` for node `i`; length MUST equal\n\t * `nodeCount`). Each node runs under its own tag so its committed writable\n\t * layer (RocksDB slivers) promotes to a DISTINCT image on snapshot restore;\n\t * a single shared tag collapses N committed layers -> 1 on the restore\n\t * image-promote, orphaning N-1 nodes' blobs. */\n\treadonly images: ReadonlyArray<ImageRef>;\n\treadonly nodeCount: number;\n\t/** Pre-allocated /24 prefix from `subnetForStack`. Example:\n\t * `'10.42.7'` (the third octet is hashed per stack). */\n\treadonly subnetPrefix: string;\n\treadonly containerApiPort: number;\n\treadonly walrusNetworkName: string;\n\treadonly suiNetworkName: string;\n\treadonly deployHostMountPath: string;\n\t/** On-disk per-stack root from `StackPathsService.stackRoot`. The\n\t * walrus bind-mount is computed by `walrusDeployMountPaths` as\n\t * `<stackRoot> -> <mountTarget>`; the deploy output dir MUST be a\n\t * descendant. Threaded explicitly to remove the previous\n\t * `dirname(dirname(dirname(...)))` walk-up footgun. */\n\treadonly stackRoot: string;\n\t/** Fingerprint of the deploy outputs mounted into each node. */\n\treadonly deployConfigHash: string;\n\treadonly stopGraceSeconds?: number;\n\treadonly readyTimeoutMs?: number;\n}\n\n/** Result of starting the committee — descriptors used by the\n * plugin's resolved value. */\nexport interface StorageNodesAcquired {\n\treadonly nodes: ReadonlyArray<WalrusStorageNode>;\n}\n\n/** Distilled-doc invariant 1: pinned IPs start at `<prefix>.10`.\n * Centralized so the deploy one-shot's `WALRUS_LISTENING_IPS` env\n * var and the per-node `--ip` pin compute from one source. */\nexport const WALRUS_NODE_IP_BASE = 10;\n\n/** Compute the public hostname for one storage node — the\n * `routerHostname(identity, 'walrus-node-' + i)` shape\n * (06-walrus.md §\"Routes registered\"). Main stack omits the stack\n * segment; non-main inserts it after the service label. */\nexport const computePublicHostname = (app: string, stack: string, nodeIndex: number): string => {\n\tconst base = `walrus-node-${nodeIndex}.${app}.localhost`;\n\treturn stack === 'main' ? base : `walrus-node-${nodeIndex}.${stack}.${app}.localhost`;\n};\n\nexport const storageNodeConfigHash = (parts: {\n\treadonly deployConfigHash: string;\n\treadonly nodeIndex: number;\n\treadonly deploySourceHostPath: string;\n\treadonly deployMountTarget: string;\n\treadonly containerApiPort: number;\n\treadonly walrusNetworkName: string;\n\treadonly suiNetworkName: string;\n}): string =>\n\t[\n\t\tparts.deployConfigHash,\n\t\t`node=${parts.nodeIndex}`,\n\t\t`mount=${parts.deploySourceHostPath}->${parts.deployMountTarget}`,\n\t\t`api=${parts.containerApiPort}`,\n\t\t`net=${parts.walrusNetworkName},${parts.suiNetworkName}`,\n\t].join('|');\n\nexport const buildWalrusNetworkName = (app: string, stack: string, walrusName: string): string =>\n\t`devstack-${app}-${stack}-walrus-${walrusName}-net`;\n\n/** Per-node TCP ready-probe interval. */\nconst NODE_READY_PROBE_INTERVAL_MS = 500;\n\n/** Walrus storage-node REST health endpoint (TLS disabled — plain HTTP\n * behind the router; see images/walrus/deploy-walrus.sh which rebinds\n * `rest_api_address` on 0.0.0.0 and sets `disable_tls: true`). The node\n * serves `GET /v1/health` once its API listener binds; the JSON body's\n * `nodeStatus` field reports the committee-sync state. */\nconst NODE_HEALTH_PATH = '/v1/health';\n\n/** Recovery / not-yet-serving markers in a `/v1/health` body. A node that\n * just recreated (fresh `docker run` from a committed/restored image — the\n * snapshot capture/restore resume) comes back up and reports a recovery\n * status while it re-syncs its committee/epoch; writing a blob to it before\n * it catches up fails the write quorum with \"Too many failures while\n * writing blob to nodes\". The boot ready-gate blocks until NONE of these\n * markers is present so the node is genuinely serving. */\nconst NODE_RECOVERY_MARKERS: ReadonlyArray<RegExp> = [\n\t/\"nodeStatus\"\\s*:\\s*\"Recovery/i,\n\t/\"nodeStatus\"\\s*:\\s*\"Standby\"/i,\n\t/\"nodeStatus\"\\s*:\\s*\"Starting\"/i,\n\t/\"isInRecovery\"\\s*:\\s*true/i,\n\t/\"inRecovery\"\\s*:\\s*true/i,\n];\n\n/** Classify a `/v1/health` 2xx body as write-ready. Biased toward NOT\n * false-negativing the boot (a too-strict classifier would time the boot\n * out on a field-name change upstream): a node whose health endpoint\n * returns 2xx is treated as serving UNLESS the body explicitly reports a\n * recovery / standby / starting status. The explicit `Active` serving\n * status is the fast-path. This gates EVERY acquire path (up / restart /\n * restore-converge / capture-resume) on write-readiness, not just\n * process-up — the snapshot survival-matrix fix. */\nconst isWriteReadyHealthBody = (body: string): boolean => {\n\tconst trimmed = body.trim();\n\tif (/\"nodeStatus\"\\s*:\\s*\"Active\"/i.test(trimmed)) return true;\n\t// Empty body from a 2xx with no payload: the listener answered but gave\n\t// no status — treat as not-yet-ready so the gate keeps polling briefly.\n\tif (trimmed.length === 0) return false;\n\treturn !NODE_RECOVERY_MARKERS.some((marker) => marker.test(trimmed));\n};\n\n/** Start the N-node committee.\n *\n * Wiring (this body is the load-bearing path):\n *\n * 1. Defense-in-depth nodeCount guard.\n * 2. Fork a parallel-strategy child scope off the caller's scope so\n * every node's `docker stop` finalizer fires concurrently on\n * outer teardown — collapses shutdown wall-time from `N×grace` to\n * `~max(grace)` (distilled-doc invariant 21).\n * 3. For each `i ∈ [0..N)`:\n * a. `ensureContainer` on the wrapper image with pinned IP,\n * label tuple, primary network attach (walrus net), recreate\n * on config-change.\n * b. TCP ready probe against `<publicHostname>:<routerPort>`\n * with bounded retries until the outer `readyTimeoutMs`.\n * 4. Run [3] under `Effect.all({concurrency: 'unbounded'})` — boot\n * parallelism collapses to ~max(perNode).\n *\n * WHAT THE SUBSTRATE STILL OWES:\n * - Secondary network attach (`Docker.networkConnect(suiNet)`).\n * `EnsureContainerSpec.networkAttach` accepts an array, so passing\n * `[walrusNet, suiNet]` would dual-home in one shot, but the\n * runtime adapter currently treats the first entry as the primary\n * and post-attaches the rest; the per-node pinned IP only attaches\n * to the primary. The dual-home is documented inline below and\n * relies on that adapter behavior. Storage nodes do not request\n * faucet funds during boot; the secondary network is retained for\n * future Sui-side in-network calls.\n * - Per-node `networkAlias` (`walrus-node-<i>.localhost`). The\n * contract doesn't expose alias plumbing yet; peer containers dial by\n * container name, which docker DNS publishes. The architecture\n * revision is tracked in `index.ts`.\n * - Stop-grace duration propagation. The contract's `stop` takes a\n * Duration but `ensureContainer` doesn't yet accept a default\n * grace; the runtime adapter defaults to 10s. RocksDB needs 20s\n * (distilled-doc invariant 22) — see opportunity below.\n */\nexport const startStorageNodes = (\n\truntime: ContainerRuntime,\n\tspec: StorageNodesSpec,\n): Effect.Effect<StorageNodesAcquired, WalrusPluginError, Scope.Scope> =>\n\tEffect.gen(function* () {\n\t\tif (spec.nodeCount < 1) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'storage-node',\n\t\t\t\t\t`storage-nodes: nodeCount must be >= 1 (got ${spec.nodeCount})`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\tif (spec.images.length !== spec.nodeCount) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'storage-node',\n\t\t\t\t\t`storage-nodes: images length (${spec.images.length}) must equal nodeCount (${spec.nodeCount}) — one distinct per-node image tag is required for restore-safe commits`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\t// Fork a parallel stop-scope. Per-node `ensureContainer` finalizers\n\t\t// fire here on outer teardown; closing the parallel scope races\n\t\t// the per-container `docker stop`s instead of summing them.\n\t\t//\n\t\t// Cascade semantics (verified against effect-v4 `Scope.ts`\n\t\t// `fork` docs — \"Closing the parent closes the child with the\n\t\t// same exit value\"): when ANY `bootOne` fails (e.g. a ready-\n\t\t// probe times out on node i), `Effect.all` interrupts the rest;\n\t\t// the failure propagates up through the encompassing\n\t\t// `Effect.scoped` boundary which closes `outerScope`; that\n\t\t// cascade-closes `nodeStopScope`, running EVERY already-acquired\n\t\t// per-node `docker stop` finalizer in parallel. The probe is\n\t\t// intentionally OUTSIDE `Scope.provide(nodeStopScope)` — its\n\t\t// failures do NOT need their own finalizer attached to the\n\t\t// stop scope; the just-started container's finalizer is already\n\t\t// there from the `ensureNode` acquire that preceded the probe.\n\t\tconst outerScope = yield* Effect.scope;\n\t\tconst nodeStopScope = yield* Scope.fork(outerScope, 'parallel');\n\n\t\tconst stopGraceSeconds = spec.stopGraceSeconds ?? DEFAULT_NODE_STOP_GRACE_SECONDS;\n\t\tconst readyTimeout = Duration.millis(spec.readyTimeoutMs ?? DEFAULT_NODE_READY_TIMEOUT_MS);\n\t\tconst deployMount = walrusDeployMountPaths({\n\t\t\tstackRoot: spec.stackRoot,\n\t\t\tdeployOutputDirHostPath: spec.deployHostMountPath,\n\t\t\tmountTarget: '/opt/walrus/runtime',\n\t\t});\n\n\t\tconst indices = Array.from({ length: spec.nodeCount }, (_, i) => i);\n\n\t\tconst bootOne = (i: number): Effect.Effect<WalrusStorageNode, WalrusPluginError, Scope.Scope> =>\n\t\t\tEffect.gen(function* () {\n\t\t\t\tconst containerIp = `${spec.subnetPrefix}.${WALRUS_NODE_IP_BASE + i}`;\n\t\t\t\tconst containerName = `devstack-${spec.app}-${spec.stack}-walrus-${spec.walrusName}-node-${i}`;\n\t\t\t\tconst nodeHostname = `dryrun-node-${i}`;\n\t\t\t\tconst publicHostname = computePublicHostname(spec.app, spec.stack, i);\n\n\t\t\t\tyield* setCurrentPluginPhase(`creating storage-node-${i} container ${containerName}`);\n\t\t\t\t// Acquire under the forked parallel stop scope so the\n\t\t\t\t// finalizer (docker stop) joins the per-node fan-out race.\n\t\t\t\tconst ensureNode: Effect.Effect<ContainerHandle, WalrusPluginError, Scope.Scope> =\n\t\t\t\t\tensureManagedContainer<WalrusPluginError>({\n\t\t\t\t\t\truntime,\n\t\t\t\t\t\tidentity: { app: spec.app, stack: spec.stack },\n\t\t\t\t\t\tplugin: 'walrus',\n\t\t\t\t\t\trole: `storage-node-${i}`,\n\t\t\t\t\t\tspec: {\n\t\t\t\t\t\t\tname: containerName,\n\t\t\t\t\t\t\t// Node `i`'s own image tag — distinct per node so its\n\t\t\t\t\t\t\t// committed RocksDB layer survives snapshot restore.\n\t\t\t\t\t\t\timage: spec.images[i]!,\n\t\t\t\t\t\t\trecreate: 'on-config-change',\n\t\t\t\t\t\t\tconfigHash: storageNodeConfigHash({\n\t\t\t\t\t\t\t\tdeployConfigHash: spec.deployConfigHash,\n\t\t\t\t\t\t\t\tnodeIndex: i,\n\t\t\t\t\t\t\t\tdeploySourceHostPath: deployMount.sourceHostPath,\n\t\t\t\t\t\t\t\tdeployMountTarget: deployMount.mountTarget,\n\t\t\t\t\t\t\t\tcontainerApiPort: spec.containerApiPort,\n\t\t\t\t\t\t\t\twalrusNetworkName: spec.walrusNetworkName,\n\t\t\t\t\t\t\t\tsuiNetworkName: spec.suiNetworkName,\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\tenv: {\n\t\t\t\t\t\t\t\tHOSTNAME: nodeHostname,\n\t\t\t\t\t\t\t\tDEPLOY_OUTPUT_DIR: deployMount.outputDirInContainer,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\tstopGraceSeconds,\n\t\t\t\t\t\t\t// Primary network owns the pinned `--ip`; the\n\t\t\t\t\t\t\t// secondary attach gives docker DNS for the sui\n\t\t\t\t\t\t\t// network. The adapter treats [0] as primary.\n\t\t\t\t\t\t\tnetworkAttach: [spec.walrusNetworkName, spec.suiNetworkName],\n\t\t\t\t\t\t\t// Storage nodes dial sui's host-bound RPC + faucet via\n\t\t\t\t\t\t\t// `host.docker.internal`. See\n\t\t\t\t\t\t\t// substrate/runtime/host-gateway.ts for the platform\n\t\t\t\t\t\t\t// rationale (Docker Desktop auto-wires; native Linux\n\t\t\t\t\t\t\t// Docker requires the explicit `--add-host`).\n\t\t\t\t\t\t\textraHosts: HOST_GATEWAY_EXTRA_HOSTS,\n\t\t\t\t\t\t\tmounts: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t// Mount the stack root and point the entrypoint at\n\t\t\t\t\t\t\t\t\t// the deploy child. Docker Desktop can reject\n\t\t\t\t\t\t\t\t\t// freshly-created nested bind sources immediately\n\t\t\t\t\t\t\t\t\t// after a wiped stack recreates them.\n\t\t\t\t\t\t\t\t\tsource: deployMount.sourceHostPath,\n\t\t\t\t\t\t\t\t\ttarget: deployMount.mountTarget,\n\t\t\t\t\t\t\t\t\treadonly: true,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t\tmapError: (cause) =>\n\t\t\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t\t\t'storage-node',\n\t\t\t\t\t\t\t\t`walrus storage-node-${i} (ip=${containerIp}) ensureContainer failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t\t\t{ cause },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t});\n\t\t\t\tconst handle: ContainerHandle = yield* Scope.provide(ensureNode, nodeStopScope);\n\n\t\t\t\t// WRITE-READY gate. A two-stage probe execed inside the\n\t\t\t\t// container against its own listener:\n\t\t\t\t//\n\t\t\t\t// 1. TCP `nc -z` — proves the in-container REST server bound\n\t\t\t\t// and is accepting connections (process-up).\n\t\t\t\t// 2. HTTP `GET /v1/health` — proves the node finished\n\t\t\t\t// re-syncing its committee/epoch and reports a SERVING\n\t\t\t\t// `nodeStatus` (write-ready). A node that just recreated\n\t\t\t\t// (the snapshot capture/restore resume = fresh `docker run`\n\t\t\t\t// from a committed/restored image) binds its port quickly\n\t\t\t\t// but stays in recovery for a while; writing a blob before\n\t\t\t\t// it is serving fails the write quorum with \"Too many\n\t\t\t\t// failures while writing blob to nodes\". Gating on\n\t\t\t\t// write-readiness HERE (in the boot ready-gate) means every\n\t\t\t\t// acquire path — up / restart / restore-converge /\n\t\t\t\t// capture-resume — inherits it, fixing the snapshot survival\n\t\t\t\t// matrix without a bespoke per-flow wait.\n\t\t\t\t//\n\t\t\t\t// `exec` only fails on daemon-level errors; a non-zero exit code\n\t\t\t\t// (port not yet bound, health not yet serving) is treated as\n\t\t\t\t// \"retry\". The\n\t\t\t\t// health body is captured to stdout and classified by\n\t\t\t\t// `isWriteReadyHealthBody`; a not-yet-serving status surfaces as\n\t\t\t\t// `ready:false` so the gate keeps polling until the deadline.\n\t\t\t\tyield* setCurrentPluginPhase(\n\t\t\t\t\t`waiting for storage-node-${i} write-readiness on 127.0.0.1:${spec.containerApiPort}`,\n\t\t\t\t);\n\t\t\t\tyield* waitForProbe({\n\t\t\t\t\tlabel: `walrus.storage-node.${i}`,\n\t\t\t\t\ttimeoutMs: Duration.toMillis(readyTimeout),\n\t\t\t\t\tintervalMs: NODE_READY_PROBE_INTERVAL_MS,\n\t\t\t\t\tprobe: () =>\n\t\t\t\t\t\truntime\n\t\t\t\t\t\t\t.exec(handle, [\n\t\t\t\t\t\t\t\t'sh',\n\t\t\t\t\t\t\t\t'-c',\n\t\t\t\t\t\t\t\t// Stage 1: TCP bind check (busybox-portable). Stage 2:\n\t\t\t\t\t\t\t\t// fetch /v1/health and print the body to stdout so the\n\t\t\t\t\t\t\t\t// result classifier can read `nodeStatus`. `curl -fs`\n\t\t\t\t\t\t\t\t// fails (non-zero) until the REST server returns 2xx.\n\t\t\t\t\t\t\t\t`nc -z 127.0.0.1 ${spec.containerApiPort} || exit 1; ` +\n\t\t\t\t\t\t\t\t\t`curl -fs http://127.0.0.1:${spec.containerApiPort}${NODE_HEALTH_PATH} || exit 1`,\n\t\t\t\t\t\t\t])\n\t\t\t\t\t\t\t.pipe(\n\t\t\t\t\t\t\t\tEffect.map((result) => {\n\t\t\t\t\t\t\t\t\t// Non-zero exit → not ready (port unbound / health\n\t\t\t\t\t\t\t\t\t// not serving yet). Exit 0 → classify the health body\n\t\t\t\t\t\t\t\t\t// for write-readiness; a not-yet-serving status keeps\n\t\t\t\t\t\t\t\t\t// the gate polling.\n\t\t\t\t\t\t\t\t\tif (result.exitCode !== 0) return exitCodeProbeResult(result);\n\t\t\t\t\t\t\t\t\tif (isWriteReadyHealthBody(result.stdout)) return true;\n\t\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\t\tready: false as const,\n\t\t\t\t\t\t\t\t\t\tdetail: { nodeStatus: 'not-serving', body: result.stdout.slice(0, 256) },\n\t\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t),\n\t\t\t\t}).pipe(\n\t\t\t\t\tEffect.mapError((cause) => {\n\t\t\t\t\t\tif (cause instanceof ProbeTimeoutError) {\n\t\t\t\t\t\t\treturn walrusPluginError(\n\t\t\t\t\t\t\t\t'storage-node',\n\t\t\t\t\t\t\t\t`storage-node-${i} never became write-ready within ${Duration.toMillis(readyTimeout)}ms ` +\n\t\t\t\t\t\t\t\t\t`(container=${containerName}, probe=127.0.0.1:${spec.containerApiPort}${NODE_HEALTH_PATH}, ` +\n\t\t\t\t\t\t\t\t\t`publicUrl=http://${publicHostname}:${WALRUS_ROUTER_PORT}). ` +\n\t\t\t\t\t\t\t\t\t`The container was created, but walrus-node did not bind its API port or did not ` +\n\t\t\t\t\t\t\t\t\t`finish re-syncing its committee/epoch to a serving nodeStatus (a node recreated from ` +\n\t\t\t\t\t\t\t\t\t`a committed/restored snapshot image must catch up before it accepts blob writes). ` +\n\t\t\t\t\t\t\t\t\t`Check the storage-node container logs for the faucet, WAL exchange, committee ` +\n\t\t\t\t\t\t\t\t\t`recovery, or walrus-node run step that stalled.`,\n\t\t\t\t\t\t\t\t{ cause: cause.lastError ?? cause.lastNotReady ?? cause },\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn walrusPluginError(\n\t\t\t\t\t\t\t'storage-node',\n\t\t\t\t\t\t\t`storage-node-${i} ready-probe exec failed: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t\t{ cause },\n\t\t\t\t\t\t);\n\t\t\t\t\t}),\n\t\t\t\t);\n\n\t\t\t\treturn {\n\t\t\t\t\tnodeIndex: i,\n\t\t\t\t\t// Stable node-id derived from name. The on-chain\n\t\t\t\t\t// public_key + bls12-381 keypair lives inside the\n\t\t\t\t\t// per-node keystore the deploy one-shot emitted;\n\t\t\t\t\t// this descriptor is the routing handle, not the\n\t\t\t\t\t// crypto identity. The SDK consumer reads the\n\t\t\t\t\t// public key off `packageConfig` rather than this\n\t\t\t\t\t// per-node descriptor.\n\t\t\t\t\tnodeId: `walrus-node-${i}`,\n\t\t\t\t\tpublicHostname,\n\t\t\t\t\t// Router-fronted URL on the well-known walrus\n\t\t\t\t\t// entrypoint port — Traefik routes by Host: header.\n\t\t\t\t\trpcUrl: `http://${publicHostname}:${WALRUS_ROUTER_PORT}`,\n\t\t\t\t} satisfies WalrusStorageNode;\n\t\t\t});\n\n\t\tconst nodes = yield* Effect.all(indices.map(bootOne), {\n\t\t\tconcurrency: 'unbounded',\n\t\t});\n\n\t\treturn { nodes };\n\t});\n"],"mappings":";;;;;;;;AA+CA,MAAa,gCAAgC;;;;;AAM7C,MAAa,qBAAqB;;;;AAKlC,MAAa,6BAA6B;;;;;AA+D1C,MAAa,yBAAyB,KAAa,OAAe,cAA8B;CAC/F,MAAM,OAAO,eAAe,UAAU,GAAG,IAAI;CAC7C,OAAO,UAAU,SAAS,OAAO,eAAe,UAAU,GAAG,MAAM,GAAG,IAAI;AAC3E;AAEA,MAAa,yBAAyB,UASrC;CACC,MAAM;CACN,QAAQ,MAAM;CACd,SAAS,MAAM,qBAAqB,IAAI,MAAM;CAC9C,OAAO,MAAM;CACb,OAAO,MAAM,kBAAkB,GAAG,MAAM;AACzC,CAAC,CAAC,KAAK,GAAG;AAEX,MAAa,0BAA0B,KAAa,OAAe,eAClE,YAAY,IAAI,GAAG,MAAM,UAAU,WAAW;;AAG/C,MAAM,+BAA+B;;;;;;AAOrC,MAAM,mBAAmB;;;;;;;;AASzB,MAAM,wBAA+C;CACpD;CACA;CACA;CACA;CACA;AACD;;;;;;;;;AAUA,MAAM,0BAA0B,SAA0B;CACzD,MAAM,UAAU,KAAK,KAAK;CAC1B,IAAI,+BAA+B,KAAK,OAAO,GAAG,OAAO;CAGzD,IAAI,QAAQ,WAAW,GAAG,OAAO;CACjC,OAAO,CAAC,sBAAsB,MAAM,WAAW,OAAO,KAAK,OAAO,CAAC;AACpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCA,MAAa,qBACZ,SACA,SAEA,OAAO,IAAI,aAAa;CACvB,IAAI,KAAK,YAAY,GACpB,OAAO,OAAO,OAAO,KACpB,kBACC,gBACA,8CAA8C,KAAK,UAAU,EAC9D,CACD;CAED,IAAI,KAAK,OAAO,WAAW,KAAK,WAC/B,OAAO,OAAO,OAAO,KACpB,kBACC,gBACA,iCAAiC,KAAK,OAAO,OAAO,0BAA0B,KAAK,UAAU,yEAC9F,CACD;CAmBD,MAAM,aAAa,OAAO,OAAO;CACjC,MAAM,gBAAgB,OAAO,MAAM,KAAK,YAAY,UAAU;CAE9D,MAAM,mBAAmB,KAAK,oBAAA;CAC9B,MAAM,eAAe,SAAS,OAAO,KAAK,kBAAA,GAA+C;CACzF,MAAM,cAAc,uBAAuB;EAC1C,WAAW,KAAK;EAChB,yBAAyB,KAAK;EAC9B,aAAa;CACd,CAAC;CAED,MAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,KAAK,UAAU,IAAI,GAAG,MAAM,CAAC;CAElE,MAAM,WAAW,MAChB,OAAO,IAAI,aAAa;EACvB,MAAM,cAAc,GAAG,KAAK,aAAa,GAAA,KAAyB;EAClE,MAAM,gBAAgB,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,UAAU,KAAK,WAAW,QAAQ;EAC3F,MAAM,eAAe,eAAe;EACpC,MAAM,iBAAiB,sBAAsB,KAAK,KAAK,KAAK,OAAO,CAAC;EAEpE,OAAO,sBAAsB,yBAAyB,EAAE,aAAa,eAAe;EAGpF,MAAM,aACL,uBAA0C;GACzC;GACA,UAAU;IAAE,KAAK,KAAK;IAAK,OAAO,KAAK;GAAM;GAC7C,QAAQ;GACR,MAAM,gBAAgB;GACtB,MAAM;IACL,MAAM;IAGN,OAAO,KAAK,OAAO;IACnB,UAAU;IACV,YAAY,sBAAsB;KACjC,kBAAkB,KAAK;KACvB,WAAW;KACX,sBAAsB,YAAY;KAClC,mBAAmB,YAAY;KAC/B,kBAAkB,KAAK;KACvB,mBAAmB,KAAK;KACxB,gBAAgB,KAAK;IACtB,CAAC;IACD,KAAK;KACJ,UAAU;KACV,mBAAmB,YAAY;IAChC;IACA;IAIA,eAAe,CAAC,KAAK,mBAAmB,KAAK,cAAc;IAM3D,YAAY;IACZ,QAAQ,CACP;KAKC,QAAQ,YAAY;KACpB,QAAQ,YAAY;KACpB,UAAU;IACX,CACD;GACD;GACA,WAAW,UACV,kBACC,gBACA,uBAAuB,EAAE,OAAO,YAAY,4BAA4B,MAAM,OAAO,IAAI,MAAM,UAC/F,EAAE,MAAM,CACT;EACF,CAAC;EACF,MAAM,SAA0B,OAAO,MAAM,QAAQ,YAAY,aAAa;EA0B9E,OAAO,sBACN,4BAA4B,EAAE,gCAAgC,KAAK,kBACpE;EACA,OAAO,aAAa;GACnB,OAAO,uBAAuB;GAC9B,WAAW,SAAS,SAAS,YAAY;GACzC,YAAY;GACZ,aACC,QACE,KAAK,QAAQ;IACb;IACA;IAKA,mBAAmB,KAAK,iBAAiB,wCACX,KAAK,mBAAmB,iBAAiB;GACxE,CAAC,CAAC,CACD,KACA,OAAO,KAAK,WAAW;IAKtB,IAAI,OAAO,aAAa,GAAG,OAAO,oBAAoB,MAAM;IAC5D,IAAI,uBAAuB,OAAO,MAAM,GAAG,OAAO;IAClD,OAAO;KACN,OAAO;KACP,QAAQ;MAAE,YAAY;MAAe,MAAM,OAAO,OAAO,MAAM,GAAG,GAAG;KAAE;IACxE;GACD,CAAC,CACF;EACH,CAAC,CAAC,CAAC,KACF,OAAO,UAAU,UAAU;GAC1B,IAAI,iBAAiB,mBACpB,OAAO,kBACN,gBACA,gBAAgB,EAAE,mCAAmC,SAAS,SAAS,YAAY,EAAE,gBACtE,cAAc,oBAAoB,KAAK,mBAAmB,iBAAiB,qBACrE,eAAe,GAAG,mBAAmB,0XAM1D,EAAE,OAAO,MAAM,aAAa,MAAM,gBAAgB,MAAM,CACzD;GAED,OAAO,kBACN,gBACA,gBAAgB,EAAE,4BAA4B,MAAM,OAAO,IAAI,MAAM,UACrE,EAAE,MAAM,CACT;EACD,CAAC,CACF;EAEA,OAAO;GACN,WAAW;GAQX,QAAQ,eAAe;GACvB;GAGA,QAAQ,UAAU,eAAe,GAAG;EACrC;CACD,CAAC;CAMF,OAAO,EAAE,OAAA,OAJY,OAAO,IAAI,QAAQ,IAAI,OAAO,GAAG,EACrD,aAAa,YACd,CAAC,EAEc;AAChB,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { walrusPluginError } from "./errors.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import { signAndDispatch } from "
|
|
4
|
-
import
|
|
2
|
+
import { formatExecutedFailure } from "../sui/exec/index.mjs";
|
|
3
|
+
import { signAndDispatch } from "../sui/exec/sign-and-dispatch.mjs";
|
|
4
|
+
import "../sui/index.mjs";
|
|
5
5
|
import { SUI_FULL_COIN_TYPE } from "../account/funding.mjs";
|
|
6
6
|
import "../account/index.mjs";
|
|
7
7
|
import { Effect, Schema } from "effect";
|
|
@@ -90,11 +90,7 @@ const swapAccountSuiForWal = (args) => Effect.gen(function* () {
|
|
|
90
90
|
onFailed: (failure) => Effect.fail(walrusPluginError("fund-wal", `walrus.fundWal: SUI -> WAL swap failed on-chain (exchange=${args.exchange.objectId}) ` + formatExecutedFailure(failure))),
|
|
91
91
|
onSuccess: (ok) => Effect.succeed({ digest: ok.digest })
|
|
92
92
|
});
|
|
93
|
-
})
|
|
94
|
-
[WalrusSpans.fundAccount]: args.account.name,
|
|
95
|
-
[WalrusSpans.fundAddress]: args.recipientAddress,
|
|
96
|
-
[WalrusSpans.fundExchange]: args.exchange.objectId
|
|
97
|
-
} }));
|
|
93
|
+
});
|
|
98
94
|
//#endregion
|
|
99
95
|
export { resolveWalExchange, swapAccountSuiForWal };
|
|
100
96
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wal-swap.mjs","names":[],"sources":["../../../src/plugins/walrus/wal-swap.ts"],"sourcesContent":["import { Effect, Schema } from 'effect';\nimport { Transaction } from '@mysten/sui/transactions';\n\nimport type { ChainProbe } from '../../contracts/chain-probe.ts';\nimport { formatExecutedFailure } from '../../substrate/runtime/sui-execute/index.ts';\nimport { signAndDispatch } from '../../substrate/runtime/sui-execute/sign-and-dispatch.ts';\nimport type { AccountValue } from '../account/index.ts';\nimport type { SuiSdkShim } from '../sui/index.ts';\nimport { SUI_FULL_COIN_TYPE } from '../account/index.ts';\nimport { walrusPluginError, type WalrusPluginError } from './errors.ts';\nimport { WalrusSpans } from './spans.ts';\n\n/** Conservative reserve held back from the gas coin for transaction\n * gas itself. The swap call splits `paymentMist` off the gas coin\n * via `tx.coin({ useGasCoin: true })`, so the on-chain balance must\n * cover BOTH the payment AND a gas budget reserve. The exact gas\n * budget is set by the SDK at build time; this reserve is a coarse\n * upper bound used only by the pre-flight refusal — if the wire\n * call proves the reserve is too small the SDK still surfaces the\n * native `InsufficientGas` cause with the real numbers. */\nconst WAL_SWAP_GAS_RESERVE_MIST = 50_000_000n;\n\nexport interface WalExchangeHandle {\n\treadonly objectId: string;\n\treadonly packageId: string;\n}\n\nexport type WalExchangeProbeKey = { readonly kind: 'object'; readonly objectId: string };\n\nexport type WalSwapSdk = Pick<SuiSdkShim, 'client'> & {\n\treadonly core: Pick<SuiSdkShim['core'], 'getBalance'>;\n};\n\n/** Read the account's SUI balance (best-effort). Returns `null` if the\n * RPC throws or the response shape is unexpected — the pre-flight is\n * a hint, not a hard gate. */\nconst readSuiBalance = (\n\tsdk: WalSwapSdk,\n\towner: string,\n): Effect.Effect<bigint | null, never> =>\n\tEffect.promise(async () => {\n\t\ttry {\n\t\t\tconst response = await sdk.core.getBalance({ owner, coinType: SUI_FULL_COIN_TYPE });\n\t\t\tconst outer =\n\t\t\t\ttypeof response === 'object' && response !== null && 'balance' in response\n\t\t\t\t\t? (response as { readonly balance?: unknown }).balance\n\t\t\t\t\t: response;\n\t\t\tconst value =\n\t\t\t\ttypeof outer === 'object' && outer !== null && 'balance' in outer\n\t\t\t\t\t? (outer as { readonly balance?: unknown }).balance\n\t\t\t\t\t: outer;\n\t\t\tif (typeof value === 'bigint') return value;\n\t\t\tif (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0)\n\t\t\t\treturn BigInt(value);\n\t\t\tif (typeof value === 'string' && /^\\d+$/.test(value)) return BigInt(value);\n\t\t\treturn null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t});\n\nexport interface WalAccountSwapRequest {\n\treadonly account: AccountValue;\n\treadonly sdk: WalSwapSdk;\n\treadonly exchange: WalExchangeHandle;\n\treadonly recipientAddress: string;\n\treadonly paymentMist: bigint;\n}\n\nconst WalExchangeObjectShape = Schema.Struct({\n\tobjectId: Schema.String,\n\ttype: Schema.String,\n});\n\nexport const resolveWalExchange = (\n\tprobe: ChainProbe<WalExchangeProbeKey>,\n\texchangeObjectId: string | undefined,\n): Effect.Effect<WalExchangeHandle | null, WalrusPluginError> =>\n\tEffect.gen(function* () {\n\t\tif (exchangeObjectId === undefined) return null;\n\t\tconst found = yield* probe\n\t\t\t.get({ kind: 'object', objectId: exchangeObjectId }, WalExchangeObjectShape, 'lenient')\n\t\t\t.pipe(\n\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t'exchange',\n\t\t\t\t\t\t`walrus.exchange: failed to resolve exchange object ${exchangeObjectId}: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t{ cause },\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\tif (found === null) return null;\n\t\tconst packageId = found.type.split('::')[0];\n\t\tif (packageId === undefined || !packageId.startsWith('0x')) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'exchange',\n\t\t\t\t\t`walrus.exchange: unexpected exchange object type \"${found.type}\" — expected \"<pkg>::wal_exchange::Exchange\"`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn { objectId: exchangeObjectId, packageId };\n\t});\n\nexport const buildWalSwapTransaction = (args: {\n\treadonly signerAddress: string;\n\treadonly recipientAddress: string;\n\treadonly exchange: WalExchangeHandle;\n\treadonly paymentMist: bigint;\n}): Transaction => {\n\tconst tx = new Transaction();\n\ttx.setSender(args.signerAddress);\n\tconst paymentCoin = tx.coin({\n\t\tbalance: args.paymentMist,\n\t\ttype: '0x2::sui::SUI',\n\t\tuseGasCoin: true,\n\t});\n\tconst walCoin = tx.moveCall({\n\t\ttarget: `${args.exchange.packageId}::wal_exchange::exchange_all_for_wal`,\n\t\targuments: [tx.object(args.exchange.objectId), paymentCoin],\n\t});\n\ttx.transferObjects([walCoin], tx.pure.address(args.recipientAddress));\n\treturn tx;\n};\n\nexport const swapAccountSuiForWal = (\n\targs: WalAccountSwapRequest,\n): Effect.Effect<{ readonly digest: string }, WalrusPluginError> =>\n\tEffect.gen(function* () {\n\t\t// Pre-flight gas-budget refusal — the swap splits `paymentMist`\n\t\t// off the gas coin via `tx.coin({ useGasCoin: true })`, so the\n\t\t// on-chain SUI balance must cover BOTH the payment AND a gas\n\t\t// reserve. Without this check the failure surfaces as an opaque\n\t\t// `Transaction.build` / chain-side `InsufficientGas` after the\n\t\t// wire call has already been attempted; the typed refusal here\n\t\t// names the numbers so the caller sees the real cause. The\n\t\t// balance read is best-effort — a `null` from the SDK falls\n\t\t// through to the wire call (the existing `mapSignError` /\n\t\t// `onFailed` paths still catch the chain-side failure).\n\t\tconst suiBalance = yield* readSuiBalance(args.sdk, args.account.address);\n\t\tconst required = args.paymentMist + WAL_SWAP_GAS_RESERVE_MIST;\n\t\tif (suiBalance !== null && suiBalance < required) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'fund-wal',\n\t\t\t\t\t`walrus.fundWal: account '${args.account.name}' (address=${args.account.address}) ` +\n\t\t\t\t\t\t`has insufficient SUI to swap ${args.paymentMist} for WAL — ` +\n\t\t\t\t\t\t`balance=${suiBalance} mist, required≥${required} mist ` +\n\t\t\t\t\t\t`(payment=${args.paymentMist} + gas reserve=${WAL_SWAP_GAS_RESERVE_MIST}). ` +\n\t\t\t\t\t\t`Top up the account's SUI funding before declaring the WAL funding entry.`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn yield* signAndDispatch({\n\t\t\tsignerSource: args.account,\n\t\t\tbuildTxBytes: () =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst tx = buildWalSwapTransaction({\n\t\t\t\t\t\tsignerAddress: args.account.address,\n\t\t\t\t\t\trecipientAddress: args.recipientAddress,\n\t\t\t\t\t\texchange: args.exchange,\n\t\t\t\t\t\tpaymentMist: args.paymentMist,\n\t\t\t\t\t});\n\t\t\t\t\treturn yield* Effect.tryPromise({\n\t\t\t\t\t\ttry: () => tx.build({ client: args.sdk.client }),\n\t\t\t\t\t\tcatch: (cause): WalrusPluginError =>\n\t\t\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t\t\t'fund-wal',\n\t\t\t\t\t\t\t\t`walrus.fundWal: transaction serialization failed for account '${args.account.name}'.`,\n\t\t\t\t\t\t\t\t{ cause },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t});\n\t\t\t\t}),\n\t\t\tmapSignError: (cause): WalrusPluginError =>\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'fund-wal',\n\t\t\t\t\t`walrus.fundWal: SUI -> WAL swap failed for ${args.recipientAddress} ` +\n\t\t\t\t\t\t`using account '${args.account.name}' (address=${args.account.address}) ` +\n\t\t\t\t\t\t`against exchange ${args.exchange.objectId}.`,\n\t\t\t\t\t{ cause },\n\t\t\t\t),\n\t\t\tonFailed: (failure) =>\n\t\t\t\tEffect.fail(\n\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t'fund-wal',\n\t\t\t\t\t\t`walrus.fundWal: SUI -> WAL swap failed on-chain ` +\n\t\t\t\t\t\t\t`(exchange=${args.exchange.objectId}) ` +\n\t\t\t\t\t\t\tformatExecutedFailure(failure),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\tonSuccess: (ok) => Effect.succeed({ digest: ok.digest }),\n\t\t});\n\t}).pipe(\n\t\tEffect.withSpan('devstack.plugin.walrus.fundWal', {\n\t\t\tattributes: {\n\t\t\t\t[WalrusSpans.fundAccount]: args.account.name,\n\t\t\t\t[WalrusSpans.fundAddress]: args.recipientAddress,\n\t\t\t\t[WalrusSpans.fundExchange]: args.exchange.objectId,\n\t\t\t},\n\t\t}),\n\t);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"wal-swap.mjs","names":[],"sources":["../../../src/plugins/walrus/wal-swap.ts"],"sourcesContent":["import { Effect, Schema } from 'effect';\nimport { Transaction } from '@mysten/sui/transactions';\n\nimport type { ChainProbe } from '../../contracts/chain-probe.ts';\nimport type { AccountValue } from '../account/index.ts';\nimport { formatExecutedFailure, signAndDispatch, type SuiSdkShim } from '../sui/index.ts';\nimport { SUI_FULL_COIN_TYPE } from '../account/index.ts';\nimport { walrusPluginError, type WalrusPluginError } from './errors.ts';\n\n/** Conservative reserve held back from the gas coin for transaction\n * gas itself. The swap call splits `paymentMist` off the gas coin\n * via `tx.coin({ useGasCoin: true })`, so the on-chain balance must\n * cover BOTH the payment AND a gas budget reserve. The exact gas\n * budget is set by the SDK at build time; this reserve is a coarse\n * upper bound used only by the pre-flight refusal — if the wire\n * call proves the reserve is too small the SDK still surfaces the\n * native `InsufficientGas` cause with the real numbers. */\nconst WAL_SWAP_GAS_RESERVE_MIST = 50_000_000n;\n\nexport interface WalExchangeHandle {\n\treadonly objectId: string;\n\treadonly packageId: string;\n}\n\nexport type WalExchangeProbeKey = { readonly kind: 'object'; readonly objectId: string };\n\nexport type WalSwapSdk = Pick<SuiSdkShim, 'client'> & {\n\treadonly core: Pick<SuiSdkShim['core'], 'getBalance'>;\n};\n\n/** Read the account's SUI balance (best-effort). Returns `null` if the\n * RPC throws or the response shape is unexpected — the pre-flight is\n * a hint, not a hard gate. */\nconst readSuiBalance = (sdk: WalSwapSdk, owner: string): Effect.Effect<bigint | null, never> =>\n\tEffect.promise(async () => {\n\t\ttry {\n\t\t\tconst response = await sdk.core.getBalance({ owner, coinType: SUI_FULL_COIN_TYPE });\n\t\t\tconst outer =\n\t\t\t\ttypeof response === 'object' && response !== null && 'balance' in response\n\t\t\t\t\t? (response as { readonly balance?: unknown }).balance\n\t\t\t\t\t: response;\n\t\t\tconst value =\n\t\t\t\ttypeof outer === 'object' && outer !== null && 'balance' in outer\n\t\t\t\t\t? (outer as { readonly balance?: unknown }).balance\n\t\t\t\t\t: outer;\n\t\t\tif (typeof value === 'bigint') return value;\n\t\t\tif (typeof value === 'number' && Number.isSafeInteger(value) && value >= 0)\n\t\t\t\treturn BigInt(value);\n\t\t\tif (typeof value === 'string' && /^\\d+$/.test(value)) return BigInt(value);\n\t\t\treturn null;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t});\n\nexport interface WalAccountSwapRequest {\n\treadonly account: AccountValue;\n\treadonly sdk: WalSwapSdk;\n\treadonly exchange: WalExchangeHandle;\n\treadonly recipientAddress: string;\n\treadonly paymentMist: bigint;\n}\n\nconst WalExchangeObjectShape = Schema.Struct({\n\tobjectId: Schema.String,\n\ttype: Schema.String,\n});\n\nexport const resolveWalExchange = (\n\tprobe: ChainProbe<WalExchangeProbeKey>,\n\texchangeObjectId: string | undefined,\n): Effect.Effect<WalExchangeHandle | null, WalrusPluginError> =>\n\tEffect.gen(function* () {\n\t\tif (exchangeObjectId === undefined) return null;\n\t\tconst found = yield* probe\n\t\t\t.get({ kind: 'object', objectId: exchangeObjectId }, WalExchangeObjectShape, 'lenient')\n\t\t\t.pipe(\n\t\t\t\tEffect.mapError((cause) =>\n\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t'exchange',\n\t\t\t\t\t\t`walrus.exchange: failed to resolve exchange object ${exchangeObjectId}: ${cause.reason}: ${cause.detail}`,\n\t\t\t\t\t\t{ cause },\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t);\n\t\tif (found === null) return null;\n\t\tconst packageId = found.type.split('::')[0];\n\t\tif (packageId === undefined || !packageId.startsWith('0x')) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'exchange',\n\t\t\t\t\t`walrus.exchange: unexpected exchange object type \"${found.type}\" — expected \"<pkg>::wal_exchange::Exchange\"`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn { objectId: exchangeObjectId, packageId };\n\t});\n\nexport const buildWalSwapTransaction = (args: {\n\treadonly signerAddress: string;\n\treadonly recipientAddress: string;\n\treadonly exchange: WalExchangeHandle;\n\treadonly paymentMist: bigint;\n}): Transaction => {\n\tconst tx = new Transaction();\n\ttx.setSender(args.signerAddress);\n\tconst paymentCoin = tx.coin({\n\t\tbalance: args.paymentMist,\n\t\ttype: '0x2::sui::SUI',\n\t\tuseGasCoin: true,\n\t});\n\tconst walCoin = tx.moveCall({\n\t\ttarget: `${args.exchange.packageId}::wal_exchange::exchange_all_for_wal`,\n\t\targuments: [tx.object(args.exchange.objectId), paymentCoin],\n\t});\n\ttx.transferObjects([walCoin], tx.pure.address(args.recipientAddress));\n\treturn tx;\n};\n\nexport const swapAccountSuiForWal = (\n\targs: WalAccountSwapRequest,\n): Effect.Effect<{ readonly digest: string }, WalrusPluginError> =>\n\tEffect.gen(function* () {\n\t\t// Pre-flight gas-budget refusal — the swap splits `paymentMist`\n\t\t// off the gas coin via `tx.coin({ useGasCoin: true })`, so the\n\t\t// on-chain SUI balance must cover BOTH the payment AND a gas\n\t\t// reserve. Without this check the failure surfaces as an opaque\n\t\t// `Transaction.build` / chain-side `InsufficientGas` after the\n\t\t// wire call has already been attempted; the typed refusal here\n\t\t// names the numbers so the caller sees the real cause. The\n\t\t// balance read is best-effort — a `null` from the SDK falls\n\t\t// through to the wire call (the existing `mapSignError` /\n\t\t// `onFailed` paths still catch the chain-side failure).\n\t\tconst suiBalance = yield* readSuiBalance(args.sdk, args.account.address);\n\t\tconst required = args.paymentMist + WAL_SWAP_GAS_RESERVE_MIST;\n\t\tif (suiBalance !== null && suiBalance < required) {\n\t\t\treturn yield* Effect.fail(\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'fund-wal',\n\t\t\t\t\t`walrus.fundWal: account '${args.account.name}' (address=${args.account.address}) ` +\n\t\t\t\t\t\t`has insufficient SUI to swap ${args.paymentMist} for WAL — ` +\n\t\t\t\t\t\t`balance=${suiBalance} mist, required≥${required} mist ` +\n\t\t\t\t\t\t`(payment=${args.paymentMist} + gas reserve=${WAL_SWAP_GAS_RESERVE_MIST}). ` +\n\t\t\t\t\t\t`Top up the account's SUI funding before declaring the WAL funding entry.`,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t\treturn yield* signAndDispatch({\n\t\t\tsignerSource: args.account,\n\t\t\tbuildTxBytes: () =>\n\t\t\t\tEffect.gen(function* () {\n\t\t\t\t\tconst tx = buildWalSwapTransaction({\n\t\t\t\t\t\tsignerAddress: args.account.address,\n\t\t\t\t\t\trecipientAddress: args.recipientAddress,\n\t\t\t\t\t\texchange: args.exchange,\n\t\t\t\t\t\tpaymentMist: args.paymentMist,\n\t\t\t\t\t});\n\t\t\t\t\treturn yield* Effect.tryPromise({\n\t\t\t\t\t\ttry: () => tx.build({ client: args.sdk.client }),\n\t\t\t\t\t\tcatch: (cause): WalrusPluginError =>\n\t\t\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t\t\t'fund-wal',\n\t\t\t\t\t\t\t\t`walrus.fundWal: transaction serialization failed for account '${args.account.name}'.`,\n\t\t\t\t\t\t\t\t{ cause },\n\t\t\t\t\t\t\t),\n\t\t\t\t\t});\n\t\t\t\t}),\n\t\t\tmapSignError: (cause): WalrusPluginError =>\n\t\t\t\twalrusPluginError(\n\t\t\t\t\t'fund-wal',\n\t\t\t\t\t`walrus.fundWal: SUI -> WAL swap failed for ${args.recipientAddress} ` +\n\t\t\t\t\t\t`using account '${args.account.name}' (address=${args.account.address}) ` +\n\t\t\t\t\t\t`against exchange ${args.exchange.objectId}.`,\n\t\t\t\t\t{ cause },\n\t\t\t\t),\n\t\t\tonFailed: (failure) =>\n\t\t\t\tEffect.fail(\n\t\t\t\t\twalrusPluginError(\n\t\t\t\t\t\t'fund-wal',\n\t\t\t\t\t\t`walrus.fundWal: SUI -> WAL swap failed on-chain ` +\n\t\t\t\t\t\t\t`(exchange=${args.exchange.objectId}) ` +\n\t\t\t\t\t\t\tformatExecutedFailure(failure),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\tonSuccess: (ok) => Effect.succeed({ digest: ok.digest }),\n\t\t});\n\t});\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-publisher.mjs","names":[],"sources":["../../src/primitives/artifact-publisher.ts"],"sourcesContent":["// ArtifactPublisher — L0 substrate primitive (architecture §10).\n//\n// Unifies the discipline that recurs across many on-chain\n// produce/verify plugins (substrate must remain service-name-blind;\n// the plugin index is the authoritative list). cache → verify →\n// produce → register on EVERY cycle.\n//\n// This is callable from any plugin; there is NO plugin-side contract\n// to implement. Plugins pass in:\n//\n// - a namespace + cache-key derivation,\n// - a verify procedure (calls ChainProbe with a typed Schema,\n// lenient mode),\n// - a produce procedure (run on miss / verify-fail),\n// - a register procedure (fires on EVERY cycle — hit AND miss).\n\nimport type { Effect, Scope } from 'effect';\n\nimport type {
|
|
1
|
+
{"version":3,"file":"artifact-publisher.mjs","names":[],"sources":["../../src/primitives/artifact-publisher.ts"],"sourcesContent":["// ArtifactPublisher — L0 substrate primitive (architecture §10).\n//\n// Unifies the discipline that recurs across many on-chain\n// produce/verify plugins (substrate must remain service-name-blind;\n// the plugin index is the authoritative list). cache → verify →\n// produce → register on EVERY cycle.\n//\n// This is callable from any plugin; there is NO plugin-side contract\n// to implement. Plugins pass in:\n//\n// - a namespace + cache-key derivation,\n// - a verify procedure (calls ChainProbe with a typed Schema,\n// lenient mode),\n// - a produce procedure (run on miss / verify-fail),\n// - a register procedure (fires on EVERY cycle — hit AND miss).\n\nimport type { Effect, Scope } from 'effect';\n\nimport type { ContentHash } from '../substrate/brand.ts';\n\n/** Input contract for ArtifactPublisher.publish. */\nexport interface ArtifactSpec<Produced, Verified> {\n\t/** Cache namespace — plugin-chosen, e.g. `package`. */\n\treadonly namespace: string;\n\t/** Chain identity (plain string value) — substrate folds into the cache key. */\n\treadonly chain: string;\n\t/** Content-hash of canonical input bytes. */\n\treadonly contentHash: ContentHash;\n\t/** Verify probe — typed Schema; lenient mode. Returns null on\n\t * not-found OR transient failure.\n\t *\n\t * The substrate decodes the cached payload (if any) and passes it\n\t * in as `cached`. Plugins that key their on-chain probe off a\n\t * field of the cached payload (e.g. action's `digest`, package's\n\t * `packageId`) read it from here directly — no in-process\n\t * registry-hop required. Plugins that don't care about the\n\t * cached payload ignore the parameter.\n\t *\n\t * When the cache is empty (cold boot) OR decode failed\n\t * (corruption) the substrate short-circuits to \"miss\" before\n\t * invoking this; callers can therefore assume `cached` is\n\t * defined on every call. */\n\treadonly verify: (cached: Produced) => Effect.Effect<Verified | null, never>;\n\t/** Produce procedure — runs on cache miss OR verify-fail. */\n\treadonly produce: Effect.Effect<Produced, ArtifactPublishError, Scope.Scope>;\n\t/** Register procedure — fires on EVERY cycle (hit AND miss). The\n\t * substrate always hands back the decoded `Produced` payload (on\n\t * cache hit) or the freshly produced one (on miss); the verify\n\t * shape is a probe-only signal, never surfaced to callers. */\n\treadonly register: (artifact: Produced) => Effect.Effect<void, never>;\n}\n\n/** Tagged error from a publish round. */\nexport interface ArtifactPublishError {\n\treadonly _tag: 'ArtifactPublishError';\n\treadonly reason: 'produce-failed' | 'verify-exhausted' | 'cache-corrupt';\n\treadonly detail: string;\n}\n\n/** Constructor for `ArtifactPublishError`. Centralising the literal\n * shape (single `_tag` site, no `as const` ceremony at call sites)\n * per STYLE_GUIDE §2: tagged errors expose a factory at every\n * plugin/public boundary. Every plugin's `produce` /\n * `Effect.mapError` path goes through this. */\nexport const artifactPublishError = (\n\treason: ArtifactPublishError['reason'],\n\tdetail: string,\n): ArtifactPublishError => ({\n\t_tag: 'ArtifactPublishError',\n\treason,\n\tdetail,\n});\n\n/** The publisher service. Plugins call `publish`; substrate handles\n * cache lookup, verify, produce-on-miss, idempotent register.\n *\n * Returns the `Produced` payload on EVERY path:\n * - cache hit + verify succeeds → the decoded cached `Produced`,\n * - cache miss or verify-fail → the freshly produced `Produced`.\n *\n * The `Verified` shape is a probe-only signal (drives the lenient\n * null/non-null decision inside the substrate); it is never returned\n * to plugin callers. Callers therefore type-narrow trivially against\n * `Produced` and avoid the `'<sentinel>'` projection dance. */\nexport interface ArtifactPublisher {\n\treadonly publish: <Produced, Verified>(\n\t\tspec: ArtifactSpec<Produced, Verified>,\n\t) => Effect.Effect<Produced, ArtifactPublishError, Scope.Scope>;\n}\n"],"mappings":";;;;;;AAgEA,MAAa,wBACZ,QACA,YAC2B;CAC3B,MAAM;CACN;CACA;AACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import { Effect } from "effect";
|
|
1
|
+
import { Effect, Scope } from "effect";
|