fhEVM@fhevm/sdk运行时兼容性完全指南:多线程、单线程与边缘运行时支持矩阵
【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm
本指南以 sdk/js-sdk/docs/runtime-compatibility.md 为核心,系统讲解@fhevm/sdk在浏览器、Node.js、Bun、Deno、Electron 与 Next.js(CSR/SSR/Edge)等环境中的运行前提、线程能力判定与降级策略。读完你将掌握:为什么“单线程在任何能编译 WASM 的环境都能跑”、多线程到底依赖哪些底层能力(SharedArrayBuffer+ Worker 后端)、以及为什么 Vercel Edge / Cloudflare Workers 无法在隔离区内直接运行 SDK——并能在自己的部署里做出正确的工程取舍。
一、SDK 运行环境的三大能力前提
@fhevm/sdk内部会加载两个 WebAssembly 模块:TFHE(加密,可多线程)与TKMS(解密,始终轻量、单线程)。因此,一个环境是否支持 SDK,最终取决于以下三项能力:
- WASM 编译能力——运行时必须允许从字节构建 WebAssembly 模块(
WebAssembly.compile)。如果 SDK 无法编译 WASM,则完全无法运行,这是硬性前提。 - 解压能力——内嵌的 WASM 以 gzip 压缩存放。SDK 优先使用平台原生
DecompressionStream,否则回退到内置的纯 JS inflater(兼容旧浏览器与部分运行时)。因此解压永远不会成为硬性阻塞。 - 线程能力(仅 TFHE 多线程需要)——多线程 TFHE 需要同时具备
SharedArrayBuffer和 worker 后端(WebWorker或node:worker_threads)。二者缺一,SDK 会优雅降级为单线程(单线程永远可用,它不需要 worker)。
核心结论:凡是能编译 WASM 的环境,单线程模式一定可用;多线程只是需要额外线程能力支撑的性能优化。
二、支持矩阵(权威速查表)
下表是 runtime-compatibility.md 中支持矩阵的完整呈现。其中“when cross-origin isolated”指页面通过Cross-Origin-Opener-Policy: same-origin与Cross-Origin-Embedder-Policy: require-corp两个响应头服务,使得crossOriginIsolated === true且SharedArrayBuffer可用。
| 环境 | SDK 运行(ST) | 多线程(MT) | MT 在此需要什么 | 备注 |
|---|---|---|---|---|
| Browser(客户端) | ✅ | ✅ 跨源隔离时 | COOP/COEP 头 →SharedArrayBuffer+ Web Workers | 零配置。无 COOP/COEP → 降级为 ST。 |
| Browser — 旧版(Firefox <113、Safari <16.4) | ✅ | ✅ 跨源隔离时 | 同上 | 无DecompressionStream→ SDK 使用纯 JS inflater。 |
| Electron(沙箱化 renderer) | ✅ | ✅ 跨源隔离时 | Web Worker(沙箱 renderer 中无worker_threads) | SDK 自动选择 Web Worker 后端。 |
| Node.js(脚本、后端、长驻服务) | ✅ | ✅ | node:worker_threads+SharedArrayBuffer(始终可用) | 无需 COOP/COEP——Node 中 SAB 恒存在。 |
| Bun | ✅ | ✅ | worker_threads | 为与 Node 保持行为一致,强制走 Node worker 后端。 |
| Deno | ✅ | ✅ 隔离时 | Web Worker +SharedArrayBuffer | Web 标准后端。 |
| Next.js — CSR(客户端组件,任意 server runtime) | ✅ | ✅ 跨源隔离时 | 浏览器SharedArrayBuffer+ Web Workers | SDK 运行在浏览器;server runtime 只提供外壳。 |
| Next.js — SSR(Node runtime)(服务端组件) | ✅ | ✅ | node:worker_threads(COOP/COEP 服务端无关) | 需要 bundler 的node:导入提示(见“Bundlers”节)。 |
| Next.js — SSR(Edge runtime)(服务端组件) | ❌ | ❌ | — | 不支持。见下文“Edge”。 |
Next.js — Edge route + CSR(runtime='edge'路由上的客户端组件) | ✅ | ✅ 跨源隔离时 | 浏览器SharedArrayBuffer+ Web Workers | 支持——SDK 在客户端运行,edge isolate 从不接触 WASM。 |
| Vercel Edge / Cloudflare Workers(在 isolate内运行 SDK) | ❌ | ❌ | — | 不支持。见下文“Edge”。 |
图例:✅ 支持 · ❌ 不支持 · “when cross-origin isolated” = 页面以Cross-Origin-Opener-Policy: same-origin+Cross-Origin-Embedder-Policy: require-corp服务(即crossOriginIsolated === true且SharedArrayBuffer可用)。
从源码看,这套矩阵正是 environment.ts 中基于能力探测而非 UA 字符串的环境判定的直接结果:isNodeLike()检查process.versions.node,isBrowserLike()要求存在location.href与addEventListener,而 Vercel Edge、Cloudflare Workers、Next.js edge 既非 Node 也非浏览器,探测返回安全值(false/undefined),调用方自然回退到 Web 标准 API。
三、SSR 与 CSR 的本质区别(元框架场景)
对于 Next.js 这类元框架,SDK 代码在哪里执行比它位于哪条路由更重要:
- CSR——SDK 运行在客户端组件中(水合后在浏览器里执行)。这是正常且完全受支持的路径。server runtime(Node或Edge)只渲染 HTML 外壳,从不编译 WASM,因此即使是 edge 渲染的路由也可用,只要 SDK 在客户端使用。
- SSR——SDK 运行在服务端组件中(在服务端渲染期间执行)。Node runtime 支持;Edge runtime 不支持。
因此“edge”并非一概不支持:edge + CSR 受支持;edge + SSR 不受支持。这是使用 Next.js 部署 fhEVM dApp 时最重要的工程判断之一。
四、为什么 Edge 运行时(服务端)跑不了 SDK
在 edge isolate 内部(Vercel Edge、Cloudflare Workers、Next.jsruntime='edge'服务端组件)运行 SDK 会失败,原因是三个相互独立的限制:
- 禁止动态 WASM 编译。Edge isolate 禁止运行时生成代码,包括从字节调用
WebAssembly.compile/instantiate。SDK 恰恰是从字节编译模块,因此被拒绝。(Next.jsdev模式在 Node 上模拟 Edge 且仅发出警告——DynamicWasmCodeGenerationWarning——所以本地看似能跑,生产环境却会失败。) - 没有
SharedArrayBuffer。Edge isolate 不暴露 SAB,因此supportsThreads为false→ 无论如何 MT 都不可能。 - 代码体积限制。TFHE 模块有数 MB(见下文),通常超过 edge 的 bundle 大小上限。
推荐方案:在 edge 部署中,从客户端组件(CSR)使用 SDK——edge runtime 负责服务页面,浏览器负责运行 SDK。
关于 TFHE 模块的体积,可在 architecture.md 中找到佐证:encrypt 模块的 TFHE WASM(ZK proof 生成)约4.9 MB,而 decrypt 模块的 TKMS WASM(份额重建)约600 KB。这也是 edge 环境代码体积限制被击穿的直接原因。
五、Bundlers:为什么消费者无需任何操作
SDK 通过动态import()加载 Node 内置模块(worker_threads、fs等),并用环境检查做守卫。打包器必须被告知不要对这些导入做静态分析,各自通过自己的 magic comment 实现——SDK 内置了全部三种:
// sdk/js-sdk/src/core/base/environment.ts 中的 _importNodeModule const id = `node:${name}`; return (await import(/* @vite-ignore */ /* webpackIgnore: true */ /* turbopackIgnore: true */ id)) as mod;@vite-ignore—— Vite;webpackIgnore: true—— webpack;turbopackIgnore: true—— Turbopack(Next.js)。没有它,Turbopack 无法分析由参数派生的模块说明符,无法把node:内置模块当作候选打包,会把调用替换成抛Cannot find module 'unknown'的 stub——这曾静默禁用 Next 服务端组件中的 Nodeworker_threads后端(→ TFHE 变为单线程)。
三个注释各自指示对应 bundler 发出原生import(),由运行时解析;在浏览器中该调用会抛错并被捕获返回undefined。SDK 消费者无需任何操作,此处仅为完整说明。
六、解压回退机制
内嵌 WASM 是 gzip 压缩的。SDK 探测是否存在可用的DecompressionStream——注意它通过实际构造一个实例来探测,因为仅做typeof检查不够:部分运行时(典型如 Next.js Edge Runtime)暴露的是构造即抛错的 stub,仅凭存在性判断是假阳性,会在编译路径深处崩溃。相关实现在 environment.ts 的supportsDecompressionStream():
export function supportsDecompressionStream(): boolean { if (_decompressionStreamSupported === undefined) { if (typeof DecompressionStream !== 'function' || typeof Blob !== 'function') { _decompressionStreamSupported = false; } else { try { // 构造即探测——Next.js Edge stub 在这里抛错;真实实现不会。 const probe = new DecompressionStream('gzip'); void probe; _decompressionStreamSupported = true; } catch { _decompressionStreamSupported = false; } } } return _decompressionStreamSupported; }当探测失败时,SDK 回退到内置、零依赖的纯 JS inflater,从而在旧浏览器(Firefox <113、Safari <16.4)及其他缺少可用DecompressionStream的运行时中依然能解压小体积的压缩载荷——无需消费者做任何事。
七、线程降级:源码级原理
多线程并非“想开就开”。在 init-p.ts 的_resolveThreadConfig()中,完整的降级逻辑如下:
- 线程数来源:
numberOfThreads未配置时取navigator.hardwareConcurrency;navigator缺失(部分 edge 运行时、Node <21)时降为 0(单线程)。numberOfThreads必须是非负整数,否则直接抛错(避免把调用者的错误静默抹平)。 - SAB 探测:线程数 > 0 时,通过
wasm-feature-detect的threads()探测SharedArrayBuffer(浏览器中 SAB 依赖 COOP/COEP 头)。探测失败则打印警告并降级单线程:
This browser does not support threads. Verify that your server returns correct headers: 'Cross-Origin-Opener-Policy': 'same-origin' 'Cross-Origin-Embedder-Policy': 'require-corp'- worker 可用性:
auto模式下若线程可用但 blob/eval worker 不可用(CSP 禁止blob:worker、Node 的--disallow-code-generation-from-strings等),同样降级单线程。 - 初始化:非单线程时才调用
tfheLib.initThreadPool(numberOfThreads)启动 worker 池;单线程直接跳过。
SDK 从不因线程问题抛错——缺少头或环境不支持线程时,只记录警告并透明降级。这也印证了文档中的结论:单线程总可用(不需要 worker,WASM 仍通过 URL 或内嵌 base64 加载)。
与之配套的 worker 后端选择在 isomorphicWorker.ts 的resolveWorkerApi()中:
| 运行时 | Web API | Node API | 选中 |
|---|---|---|---|
| 浏览器(window / web worker) | 有 | 无 | web |
| 沙箱化 Electron renderer | 有 | 无 | web |
| Node.js | 无 | 有 | node |
| jsdom(Vitest) | 无 | 有 | node |
| Deno | 有 | 有 | web |
| Bun | 有 | 有 | node(强制,与 Node 保持一致) |
注意:沙箱化 Electron renderer 虽process.versions.node已设置,但node:worker_threads不可用——由于 Web 优先策略,它会自动走 Web Worker 后端,这正是支持矩阵中“Electron 沙箱 renderer”一行的实现依据。
八、实战配置建议
1. 浏览器启用多线程:设置 COOP/COEP 头
由托管应用的服务器设置:
Cross-Origin-Opener-Policy: same-origin Cross-Origin-Embedder-Policy: require-corp缺头时浏览器禁用SharedArrayBuffer,SDK 自动回退单线程(见 runtime-configuration.md)。
2. 强制单线程
为最大化兼容性、或无法设置响应头时,显式关闭线程:
import { setFhevmRuntimeConfig } from '@fhevm/sdk/ethers'; // 或:from '@fhevm/sdk/viem' setFhevmRuntimeConfig({ singleThread: true });注意setFhevmRuntimeConfig按适配器隔离——@fhevm/sdk/ethers与@fhevm/sdk/viem各自持有独立配置,必须从你创建 client 的同一适配器导入调用;若同时使用两个适配器,需分别配置。它在创建任何 client 之前调用一次,重复调用相同配置为 no-op,不同配置则抛错。
3. 需要性能时显式指定线程数
setFhevmRuntimeConfig({ numberOfThreads: 8 }); const client = createFhevmClient({ chain: sepolia, provider }); await client.init(); // 现在编译 WASMnumberOfThreads: 0同样强制单线程。构造 client 不做任何 I/O,WASM 编译的时机由你通过client.init()/client.ready掌控。
4. Edge 部署的铁律
若使用 Vercel Edge / Cloudflare Workers / Next.jsruntime='edge',SDK 只能从客户端组件(CSR)使用。edge 运行时服务页面,浏览器运行 SDK——这是官方推荐且在矩阵中受支持的唯一 edge 姿势。
5. 关注 WASM 体积与加载
TFHE WASM 约 4.9 MB、TKMS 约 600 KB。加密客户端(createFhevmEncryptClient)只扩展 encrypt 模块,bundler 不会打入 decrypt 的 WASM——按需选择 client 工厂即可控制打包体积。WASM/worker 资产的托管、locateFile、wasmAssetLoadMode与版本固定(moduleVersions)等加载细节,详见 runtime-configuration.md。
九、相关文档
- 运行时配置 —— 线程、COOP/COEP 与 WASM 资产加载的完整配置项。
- Clients —— 加载这些 WASM 模块的 client 工厂。
- 架构 —— loader 背后的运行时与模块设计。
- 环境能力探测源码 —— 运行时识别、Node 内置模块动态导入与
DecompressionStream探测。 - 同构 Worker 源码 —— worker 后端选择矩阵与 blob/eval worker 冒烟测试。
- TFHE 模块初始化源码 —— 线程配置解析、SAB 探测与降级策略。
【免费下载链接】fhevmFHEVM, a full-stack framework for integrating Fully Homomorphic Encryption (FHE) with blockchain applications项目地址: https://gitcode.com/GitHub_Trending/fh/fhevm
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考