fhEVM `@fhevm/sdk` 运行时兼容性完全指南:多线程、单线程与边缘运行时支持矩阵
2026/9/13 19:38:00 网站建设 项目流程

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,最终取决于以下三项能力:

  1. WASM 编译能力——运行时必须允许从字节构建 WebAssembly 模块(WebAssembly.compile)。如果 SDK 无法编译 WASM,则完全无法运行,这是硬性前提。
  2. 解压能力——内嵌的 WASM 以 gzip 压缩存放。SDK 优先使用平台原生DecompressionStream,否则回退到内置的纯 JS inflater(兼容旧浏览器与部分运行时)。因此解压永远不会成为硬性阻塞
  3. 线程能力(仅 TFHE 多线程需要)——多线程 TFHE 需要同时具备SharedArrayBuffer和 worker 后端(WebWorkernode:worker_threads)。二者缺一,SDK 会优雅降级为单线程(单线程永远可用,它不需要 worker)。

核心结论:凡是能编译 WASM 的环境,单线程模式一定可用;多线程只是需要额外线程能力支撑的性能优化。

二、支持矩阵(权威速查表)

下表是 runtime-compatibility.md 中支持矩阵的完整呈现。其中“when cross-origin isolated”指页面通过Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp两个响应头服务,使得crossOriginIsolated === trueSharedArrayBuffer可用。

环境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_threadsSDK 自动选择 Web Worker 后端。
Node.js(脚本、后端、长驻服务)node:worker_threads+SharedArrayBuffer(始终可用)无需 COOP/COEP——Node 中 SAB 恒存在。
Bunworker_threads为与 Node 保持行为一致,强制走 Node worker 后端。
Deno✅ 隔离时Web Worker +SharedArrayBufferWeb 标准后端。
Next.js — CSR(客户端组件,任意 server runtime)✅ 跨源隔离时浏览器SharedArrayBuffer+ Web WorkersSDK 运行在浏览器;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 + CSRruntime='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 === trueSharedArrayBuffer可用)。

从源码看,这套矩阵正是 environment.ts 中基于能力探测而非 UA 字符串的环境判定的直接结果:isNodeLike()检查process.versions.nodeisBrowserLike()要求存在location.hrefaddEventListener,而 Vercel Edge、Cloudflare Workers、Next.js edge 既非 Node 也非浏览器,探测返回安全值(false/undefined),调用方自然回退到 Web 标准 API。

三、SSR 与 CSR 的本质区别(元框架场景)

对于 Next.js 这类元框架,SDK 代码在哪里执行比它位于哪条路由更重要:

  • CSR——SDK 运行在客户端组件中(水合后在浏览器里执行)。这是正常且完全受支持的路径。server runtime(NodeEdge)只渲染 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 会失败,原因是三个相互独立的限制:

  1. 禁止动态 WASM 编译。Edge isolate 禁止运行时生成代码,包括从字节调用WebAssembly.compile/instantiate。SDK 恰恰是从字节编译模块,因此被拒绝。(Next.jsdev模式在 Node 上模拟 Edge 且仅发出警告——DynamicWasmCodeGenerationWarning——所以本地看似能跑,生产环境却会失败。)
  2. 没有SharedArrayBufferEdge isolate 不暴露 SAB,因此supportsThreadsfalse→ 无论如何 MT 都不可能。
  3. 代码体积限制。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_threadsfs等),并用环境检查做守卫。打包器必须被告知不要对这些导入做静态分析,各自通过自己的 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(),由运行时解析;在浏览器中该调用会抛错并被捕获返回undefinedSDK 消费者无需任何操作,此处仅为完整说明。

六、解压回退机制

内嵌 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()中,完整的降级逻辑如下:

  1. 线程数来源numberOfThreads未配置时取navigator.hardwareConcurrencynavigator缺失(部分 edge 运行时、Node <21)时降为 0(单线程)。numberOfThreads必须是非负整数,否则直接抛错(避免把调用者的错误静默抹平)。
  2. SAB 探测:线程数 > 0 时,通过wasm-feature-detectthreads()探测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'
  1. worker 可用性auto模式下若线程可用但 blob/eval worker 不可用(CSP 禁止blob:worker、Node 的--disallow-code-generation-from-strings等),同样降级单线程。
  2. 初始化:非单线程时才调用tfheLib.initThreadPool(numberOfThreads)启动 worker 池;单线程直接跳过。

SDK 从不因线程问题抛错——缺少头或环境不支持线程时,只记录警告并透明降级。这也印证了文档中的结论:单线程总可用(不需要 worker,WASM 仍通过 URL 或内嵌 base64 加载)。

与之配套的 worker 后端选择在 isomorphicWorker.ts 的resolveWorkerApi()中:

运行时Web APINode API选中
浏览器(window / web worker)web
沙箱化 Electron rendererweb
Node.jsnode
jsdom(Vitest)node
Denoweb
Bunnode(强制,与 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(); // 现在编译 WASM

numberOfThreads: 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 资产的托管、locateFilewasmAssetLoadMode与版本固定(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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询