BSC 节点中的 Clef 签名器实战指南:初始化、规则引擎与 Geth 集成 📅 发布时间:2026/9/18 20:56:55 👁 浏览次数: BSC 节点中的 Clef 签名器实战指南初始化、规则引擎与 Geth 集成【免费下载链接】bscA BNB Smart Chain client based on the go-ethereum fork项目地址: https://gitcode.com/GitHub_Trending/bs/bsc本指南以本仓库基于 go-ethereum 分叉的 BNB Smart Chain 客户端自带的 Clef 教程 cmd/clef/tutorial.md 为主体系统讲解 Clef 的初始化、外部 API 交互、基于 JavaScript 的自动审批规则rules、凭据管理与 Geth 集成。读完本文你将掌握如何在 BSC 客户端中独立运行一个「签名器守护进程」让交易签名与节点解耦并通过--signer让 Geth 使用远程 Clef 作为账户后端。Clef 是 go-ethereum 体系中用于替代 Geth 内建账户管理的签名工具当 DApp 或节点需要签名数据或交易时它把待签内容发送给 Clef由 Clef 向用户展示上下文并请求许可用户批准后Clef 完成签名并返回结果。其详细定位与全部命令行选项可参见 cmd/clef/README.md。Clef 可以以守护进程方式运行在本地机器、U 盘如 USB armory甚至独立虚拟机QubesOS中从而让 DApp 即使连接到一个不可信或没有账户管理能力的远程节点也能完成本地签名。Clef 交易签名流程图初始化 Clef生成加密主种子master seedClef 需要自己存储一部分数据这些数据可能是敏感的密码、签名规则、账户信息因此Clef 的整个存储都是加密的。第一步是使用clef init用随机数生成一个 master seed这个种子本身再用你选择的密码加密$ clef init WARNING! Clef is an account management tool. It may, like any software, contain bugs. Please take care to - backup your keystore files, - verify that the keystore(s) can be opened with your password. Clef is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. Enter ok to proceed: ok The master seed of clef will be locked with a password. Please specify a password. Do not forget this password! Password: Repeat password: A master seed has been generated into /home/martin/.clef/masterseed.json This is required to be able to store credentials, such as: * Passwords for keystores (used by rule engine) * Storage for JavaScript auto-signing rules * Hash of JavaScript rule-file You should treat masterseed.json with utmost secrecy and make a backup of it! * The password is necessary but not enough, you need to back up the master seed too! * The master seed does not contain your accounts, those need to be backed up separately!为便于阅读本文后续内容省略了 WARNING 提示、用户确认以及解锁 master seed 的输出。从源码看clef init的实际行为在 cmd/clef/main.go 的initializeSecrets中它从crypto/rand读取 256 字节随机数作为 master seed使用keystore.StandardScryptN/StandardScryptP参数若指定--lightkdf则使用LightScryptN/LightScryptP以降低 KDF 强度换取更少的内存与 CPU 开销加密后写入权限为0400的masterseed.json如果该文件已存在会拒绝覆盖master key ... already exists, will not overwrite。checkFile还会校验文件权限Unix 下若存在非用户可读写的权限位mode0377 ! 0会直接报错见 cmd/clef/main.go。因此请牢记两条备份要点密码是必需的但仅凭密码还不够——必须同时备份 master seed 文件master seed 中不包含你的账户账户需要单独备份 keystore 文件。远程交互通过外部 API 操作 ClefClef 同时管理keystore 文件账户与硬件钱包Ledger、Trezor。因为 Clef 本身没有链后端不知道自己运行在哪个网络上所以启动时需要显式指定 keystore 路径与用于签名的 chain ID。教程中以 Rinkeby 测试网chain ID 4为例$ clef --keystore ~/.ethereum/rinkeby/keystore --chainid 4 INFO [07-01|11:00:46.385] Starting signer chainid4 keystore$HOME/.ethereum/rinkeby/keystore light-kdffalse advancedfalse DEBUG[07-01|11:00:46.389] FS scan times list3.521941ms set9.017µs diff4.112µs DEBUG[07-01|11:00:46.391] Ledger support enabled DEBUG[07-01|11:00:46.391] Trezor support enabled via HID DEBUG[07-01|11:00:46.391] Trezor support enabled via WebUSB INFO [07-01|11:00:46.391] Audit logs configured fileaudit.log DEBUG[07-01|11:00:46.392] IPC registered namespaceaccount INFO [07-01|11:00:46.392] IPC endpoint opened url$HOME/.clef/clef.ipc ------- Signer info ------- * intapi_version : 7.0.0 * extapi_version : 6.0.0 * extapi_http : n/a * extapi_ipc : $HOME/.clef/clef.ipc默认情况下 Clef 以CLI命令行模式启动任意远程进程都可以请求账户操作例如签名一笔交易但每次都需要用户单独确认。Starting signer一行中的chainid、keystore、light-kdf、advanced字段分别来自启动参数对应 cmd/clef/main.go 中的chainIdFlag、keystoreFlag、utils.LightKDFFlag与advancedMode。用 netcat 测试 account_list通过外部 API 端点请求 Clef 列出所有账户echo {id: 1, jsonrpc: 2.0, method: account_list} | nc -U ~/.clef/clef.ipc这会在 Clef 的 CLI 中弹出确认/拒绝提示-------- List Account request-------------- A request has been made to list all accounts. You can select which accounts the caller can see [x] 0xD9C9Cd5f6779558b6e0eD4e6Acf6b1947E7fA1F3 URL: keystore://$HOME/.ethereum/rinkeby/keystore/UTC--2017-04-14T15-15-00.327614556Z--d9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3 [x] 0x086278A6C067775F71d6B2BB1856Db6E28c30418 URL: keystore://$HOME/.ethereum/rinkeby/keystore/UTC--2018-02-06T22-53-11.211657239Z--086278a6c067775f71d6b2bb1856db6e28c30418 ------------------------------------------- Request context: NA - NA - NA Additional HTTP header data, provided by the external caller: User-Agent: Origin: Approve? [y/N]: 批准或拒绝后原始的 NetCat 进程会分别收到{jsonrpc:2.0,id:1,result:[0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3,0x086278a6c067775f71d6b2bb1856db6e28c30418]} 或 {jsonrpc:2.0,id:1,error:{code:-32000,message:Request denied}}除了列出账户你还可以请求创建新账户、签名交易、签名数据以及恢复签名ecrecover。外部 API 的完整方法清单与版本变更分别记录在 cmd/clef/README.mdExternal API 一节和 cmd/clef/extapi_changelog.md 中。设计要点外部 API 能做的事情被刻意限制得很小目的是尽可能削弱远程调用的能力。Clef 另外还有一个功能丰富得多的内部 APIUI API供 UI 使用可以支撑自定义界面其消息数据结构定义在 cmd/clef/datatypes.md 与 cmd/clef/intapi_changelog.md 中。外部 API 的 JSON-RPC 方法速览结合 cmd/clef/README.md外部 API 以 JSON-RPC 2.0 为标准通过 HTTP--http.addr:--http.port默认localhost:8550或 IPC--ipcpath默认$HOME/.clef/clef.ipc暴露所有十六进制值必须带0x前缀。核心方法包括方法作用关键参数account_new生成新私钥并按 web3 keystore 规范加密存入 keystore 目录无account_list列出该签名器当前管理的全部账户无account_signTransaction签名交易返回 RLP 编码与 JSON 两种形式的已签名交易交易对象from/to/gas/gasPrice/value/data/nonce 可选的方法签名用于解码 calldata如safeSend(address)account_signData签名一段数据返回签名content typetext/validator、application/clique、text/plain account dataaccount_signTypedData对符合 EIP-712 的结构化数据签名account EIP-712 类型化数据对象account_ecRecover从text/plain签名中恢复签名地址data signatureaccount_version获取外部 API 版本号无一个通过 HTTP 发起签名交易的 Bash 示例在 cmd/clef/README.md 中有完整展开curl -H Content-Type: application/json -X POST --data {jsonrpc:2.0,method:account_signTransaction,params:[{from:0x694267f14675d7e1b9494fd8d72fefe1755710fa,gas:0x333,gasPrice:0x1,nonce:0x0,to:0x07a565b7ed7d7a678680a4c162885bedbb695fe0, value:0x0, data:0x4401a6e40000000000000000000000000000000000000000000000000000000000000012},safeSend(address)],id:67} http://localhost:8550/自动规则让 Clef 免确认自动签名对大多数用户而言逐笔手动确认是最稳妥的方式。但在 Rinkeby 或其他 PoA 网络上运行签名器时自动规则就非常有用。首先创建一个规则文件自动允许任何人列出可用账户。规则文件是一个你可以任意编程的 JavaScript 小片段function ApproveListing() { return Approve }Attest对规则文件进行哈希背书Clef 当然不会直接运行你给的任意脚本——如果有人篡改了你的规则文件直接运行会非常危险因此需要显式attest背书规则文件即把它的哈希注入 Clef 的安全存储$ sha256sum rules.js 645b58e4f945e24d0221714ff29f6aa8e860382ced43490529db1695f5fcc71c rules.js $ clef attest 645b58e4f945e24d0221714ff29f6aa8e860382ced43490529db1695f5fcc71c Decrypt master seed of clef Password: INFO [07-01|13:25:03.290] Ruleset attestation updated sha256645b58e4f945e24d0221714ff29f6aa8e860382ced43490529db1695f5fcc71c从源码看attest命令cmd/clef/main.go 的attestFile先解密 master seed再用派生密钥打开位于 vault 目录下的加密config.json把传入的 sha256 写入键ruleset_sha256。启动时cmd/clef/main.goClef 会重新计算规则文件的 SHA-256 并与存储的哈希比对只有两者一致才会启用规则引擎否则记录Rule hash not attested, disabling并禁用规则。带规则启动 Clef$ clef --keystore ~/.ethereum/rinkeby/keystore --chainid 4 --rules rules.js INFO [07-01|13:39:49.726] Rule engine configured filerules.js INFO [07-01|13:39:49.726] Starting signer chainid4 keystore$HOME/.ethereum/rinkeby/keystore light-kdffalse advancedfalse DEBUG[07-01|13:39:49.727] Ledger support enabled DEBUG[07-01|13:39:49.727] Trezor support enabled via HID DEBUG[07-01|13:39:49.727] Trezor support enabled via WebUSB INFO [07-01|13:39:49.728] Audit logs configured fileaudit.log DEBUG[07-01|13:39:49.728] IPC registered namespaceaccount INFO [07-01|13:39:49.728] IPC endpoint opened url$HOME/.clef/clef.ipc ------- Signer info ------- * intapi_version : 7.0.0 * extapi_version : 6.0.0 * extapi_http : n/a * extapi_ipc : $HOME/.clef/clef.ipc此后任何账户列表请求都会被规则文件自动批准$ echo {id: 1, jsonrpc: 2.0, method: account_list} | nc -U ~/.clef/clef.ipc {jsonrpc:2.0,id:1,result:[0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3,0x086278a6c067775f71d6b2bb1856db6e28c30418]}揭开底层Clef 的目录与加密存储完成上述操作后~/.clef下会生成如下文件$ ls -laR ~/.clef/ $HOME/.clef/: total 24 drwxr-x--x 3 user user 4096 Jul 1 13:45 . drwxr-xr-x 102 user user 12288 Jul 1 13:39 .. drwx------ 2 user user 4096 Jul 1 13:25 02f90c0603f4f2f60188 -r-------- 1 user user 868 Jun 28 13:55 masterseed.json $HOME/.clef/02f90c0603f4f2f60188: total 12 drwx------ 2 user user 4096 Jul 1 13:25 . drwxr-x--x 3 user user 4096 Jul 1 13:45 .. -rw------- 1 user user 159 Jul 1 13:25 config.json $ cat ~/.clef/02f90c0603f4f2f60188/config.json {ruleset_sha256:{iv:SWWEtnlRIwfG7,c:I3fjmwmamxVcfGax7D0MdUOL29/rBWcs73WBILmYK0o1CrX7wSMc3y37KsmtlZUAjp0oItYq01Ow8VGUOzilG91tDHInB5YHNtm/YkufEbo}}在$HOME/.clef中masterseed.json包含 master seed。该种子被用来派生若干派生数据Vault 位置本例为02f90c0603f4f2f60188。其计算方式见 cmd/clef/main.go是keccak256(vault || masterSeed)的前 10 字节的十六进制表示。如果使用不同的 master seed例如通过clef --signersecret /path/to/file指定就会得到互不冲突的另一个 vault 位置——这让你可以运行多个 Clef 实例各自携带独立规则例如主网 测试网。config.json加密的键/值配置存储目前只包含ruleset_sha256键即要使用的自动规则的已背书哈希。密钥派生同样发生在 cmd/clef/main.gocredentials、jsstorage、config三个域分别派生独立的加密密钥对应三个文件credentials.jsonkeystore 密码凭据、jsstorage.jsonJS 规则引擎的持久化存储与config.json配置。这些文件均由storage.NewAESEncryptedStorage使用 AES-GCM 加密实现见 signer/storage/aes_gcm_storage.go。高级规则自动签名带凭据的账户要让规则真正有用例如自动签名交易签名器需要能访问解锁 keystore 所需的密码。可以通过clef setpw注入解锁密码$ clef setpw 0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3 Please enter a password to store for this address: Password: Repeat password: Decrypt master seed of clef Password: INFO [07-01|14:05:56.031] Credential store updated key0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3对应的移除命令是clef delpw address。setpw的实现见 cmd/clef/main.go密码以地址为键写入 vault 下的credentials.json加密存储。现在更新规则让新凭据发挥作用function ApproveListing() { return Approve } function ApproveSignData(req) { if (req.address.toLowerCase() 0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3) { if (req.messages[0].value.indexOf(bazonk) 0) { return Approve } return Reject } // Otherwise goes to manual processing }这个示例的含义任何用账户0xd9c9...签名数据的请求若消息包含bazonk自动批准若消息不包含bazonk自动拒绝其他任何请求转入人工确认流程。注意要复现本示例请使用你自己的账户。你可以通过 Clef 或传统账户 CLI 工具创建新账户若用后者请确保运行 Clef 时指定--keystore path/to/your/keystore让 Clef 与 Geth 使用同一个 keystore。为新的规则文件背书使 Clef 接受加载$ sha256sum rules.js f163a1738b649259bb9b369c593fdc4c6b6f86cc87e343c3ba58faee03c2a178 rules.js $ clef attest f163a1738b649259bb9b369c593fdc4c6b6f86cc87e343c3ba58faee03c2a178 Decrypt master seed of clef Password: INFO [07-01|14:11:28.509] Ruleset attestation updated sha256f163a1738b649259bb9b369c593fdc4c6b6f86cc87e343c3ba58faee03c2a178用新规则重启 Clef$ clef --keystore ~/.ethereum/rinkeby/keystore --chainid 4 --rules rules.js INFO [07-01|14:12:41.636] Rule engine configured filerules.js INFO [07-01|14:12:41.636] Starting signer chainid4 keystore$HOME/.ethereum/rinkeby/keystore light-kdffalse advancedfalse DEBUG[07-01|14:12:41.636] FS scan times list46.722µs set4.47µs diff2.157µs DEBUG[07-01|14:12:41.637] Ledger support enabled DEBUG[07-01|14:12:41.637] Trezor support enabled via HID DEBUG[07-01|14:12:41.638] Trezor support enabled via WebUSB INFO [07-01|14:12:41.638] Audit logs configured fileaudit.log DEBUG[07-01|14:12:41.638] IPC registered namespaceaccount INFO [07-01|14:12:41.638] IPC endpoint opened url$HOME/.clef/clef.ipc ------- Signer info ------- * intapi_version : 7.0.0 * extapi_version : 6.0.0 * extapi_http : n/a * extapi_ipc : $HOME/.clef/clef.ipc验证规则带 bazonk 与不带 bazonk 各签一次$ echo {id: 1, jsonrpc:2.0, method:account_signData, params:[data/plain, 0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3, 0x202062617a6f6e6b2062617a2067617a0a]} | nc -U ~/.clef/clef.ipc {jsonrpc:2.0,id:1,result:0x4f93e3457027f6be99b06b3392d0ebc60615ba448bb7544687ef1248dea4f5317f789002df783979c417d969836b6fda3710f5bffb296b4d51c8aaae6e2ac4831c} $ echo {id: 1, jsonrpc:2.0, method:account_signData, params:[data/plain, 0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3, 0x2020626f6e6b2062617a2067617a0a]} | nc -U ~/.clef/clef.ipc {jsonrpc:2.0,id:1,error:{code:-32000,message:Request denied}}同时在 Clef 的输出日志中可以看到INFO [02-21|14:42:41] Op approved INFO [02-21|14:42:56] Op rejected签名器还会把所有外部 API 流量写入日志文件末尾 4 行正是上面两次请求及其响应$ tail -n 4 audit.log t2019-07-01T15:52:140300 lvlinfo msgSignData apisigner typerequest metadata{\remote\:\NA\,\local\:\NA\,\scheme\:\NA\,\User-Agent\:\\,\Origin\:\\} addr0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3 [chksum INVALID] data0x202062617a6f6e6b2062617a2067617a0a content-typedata/plain t2019-07-01T15:52:140300 lvlinfo msgSignData apisigner typeresponse data4f93e3457027f6be99b06b3392d0ebc60615ba448bb7544687ef1248dea4f5317f789002df783979c417d969836b6fda3710f5bffb296b4d51c8aaae6e2ac4831c errornil t2019-07-01T15:52:230300 lvlinfo msgSignData apisigner typerequest metadata{\remote\:\NA\,\local\:\NA\,\scheme\:\NA\,\User-Agent\:\\,\Origin\:\\} addr0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3 [chksum INVALID] data0x2020626f6e6b2062617a2067617a0a content-typedata/plain t2019-07-01T15:52:230300 lvlinfo msgSignData apisigner typeresponse data errorRequest denied编写自动规则的更多细节含限流窗口、白名单等完整示例见 cmd/clef/rules.md。规则引擎的底层原理规则引擎的实现位于 signer/rules/rules.go。它实现了一个UIClientAPI即 UI 协议中定义的那组方法每次调用都会实例化一个全新的 JS 虚拟机goja.New()因此全局变量无法在两次调用之间保留——如需持久化数据必须使用磁盘支持的storage注入原生对象consolelog/error输出到 stderr与storageput/get值传空串即删除键预加载bignumber.js作为唯一的库deps.BigNumberJS来自 internal/jsre/deps运行规则脚本后调用对应方法参数一律以对象键值形式传入先 JSON 序列化再反序列化避免参数顺序错误。规则执行有三种可能结果见 cmd/clef/rules.mdJS 返回值行为Approve自动批准该请求Reject自动拒绝该请求发生错误或返回其他值转交给nextUI即常规人工确认通道需要注意的规则语言限制cmd/clef/rules.md 的 Things to noteuse strict会被解析但无实际效果正则引擎不完全兼容 ECMA5 规范goja 面向 ES5ES6 特性如 Typed Arrays不受支持规则执行无法加载外部 JS 文件每个调用都在全新 VM 中进行。规则文件内容被篡改后必须重新attest否则 Clef 会拒绝启用规则哈希不匹配即禁用见 cmd/clef/main.go。Geth 集成--signer使用远程 Clef 作为账户后端Clef 的价值在于它只暴露 35 个方法理想情况下社区 DApp、MetaMask、MyCrypto 等都可以直接请求签名。在此之前Geth 已经率先铺路Geth v1.9.0 起通过--signer API endpoint内置支持把本地或远程 Clef 实例当作账户后端。用之前的规则在 Rinkeby 上运行 Clef此时建议允许自动列出账户因为 Geth 时不时会拉取账户列表$ clef --keystore ~/.ethereum/rinkeby/keystore --chainid 4 --rules rules.js在另一个窗口启动 Geth列出账户甚至列出钱包以观察账户来源$ geth --rinkeby --signer~/.clef/clef.ipc console eth.accounts [0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3, 0x086278a6c067775f71d6b2bb1856db6e28c30418] personal.listWallets [{ accounts: [{ address: 0xd9c9cd5f6779558b6e0ed4e6acf6b1947e7fa1f3, url: extapi://$HOME/.clef/clef.ipc }, { address: 0x086278a6c067775f71d6b2bb1856db6e28c30418, url: extapi://$HOME/.clef/clef.ipc }], status: ok [version6.0.0], url: extapi://$HOME/.clef/clef.ipc }] eth.sendTransaction({from: eth.accounts[0], to: eth.accounts[0]})最后当我们请求发送一笔交易时Clef 会在原窗口提示用户批准--------- Transaction request------------- to: 0xD9C9Cd5f6779558b6e0eD4e6Acf6b1947E7fA1F3 from: 0xD9C9Cd5f6779558b6e0eD4e6Acf6b1947E7fA1F3 [chksum ok] value: 0 wei gas: 0x5208 (21000) gasprice: 1000000000 wei nonce: 0x2366 (9062) Request context: NA - NA - NA Additional HTTP header data, provided by the external caller: User-Agent: Origin: ------------------------------------------- Approve? [y/N]: y注意在 Geth 中启用外部签名器后端后所有其他账户管理功能都会被禁用——因为长期规划是逐步把账户管理从 Geth 中移除。从源码看这一集成由两部分构成Geth 侧--signer标志定义在 cmd/utils/flags.goGeth 在 cmd/geth/config.go 中调用external.NewExternalBackend创建外部签名后端配置上外部签名器与本地签名器是二选一的关系For now, were using EITHER external signer OR local signers且--developer与--signer互斥cmd/utils/flags.go。后端实现ExternalBackend与ExternalSigner位于 accounts/external/backend.go它通过 RPC 客户端代理请求到 Clef 的 IPC/HTTP 端点并把相关请求头User-Agent、Origin等一并转发供 Clef 在 UI 中展示请求上下文。结语与进一步阅读至此你已经走通了 Clef 的完整使用链路init初始化加密主种子 → 以指定 keystore 与 chain ID 启动守护进程 → 通过外部 APIIPC/HTTP交互 → 编写 JS 规则并attest背书 →setpw注入凭据实现自动签名 → 最后通过 Geth 的--signer把它接入节点。Clef 的安全模型可概括为一个负责全部密码学操作的独立组件暴露一个被严格视为不可信untrusted的外部 API并通过受信的 stdin/stdout 通道与 UI 通信详见 cmd/clef/README.md 的 Security model 一节与 cmd/clef/docs/setup.md 的部署配置说明。继续深入可参考cmd/clef/rules.md完整规则引擎规范与限流、白名单等高级示例cmd/clef/extapi_changelog.md 与 cmd/clef/intapi_changelog.md内外部 API 版本变更记录cmd/clef/datatypes.mdClef 与外部 UI 之间的通信消息数据结构cmd/clef/tests/testsigner.js一个直接以geth --signer http://localhost:8550联动的自动化测试脚本signer/core/api.go 与 signer/rules/rules.go签名 API 与规则引擎的核心实现。【免费下载链接】bscA BNB Smart Chain client based on the go-ethereum fork项目地址: https://gitcode.com/GitHub_Trending/bs/bsc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考