非托管钱包是一种系统,用户独自控制授权交易的私钥;任何第三方都无法移动或冻结资金。本文解释了底层的密钥管理模型,展示了如何使用标准库和 RPC 端点构建并测试一个最小的非托管签名工作流,并提供了一个可复现的流程来验证密钥从未离开客户端。文章还涵盖了常见故障模式、热存储与冷存储之间的权衡,以及如何在不依赖供应商声明的情况下衡量钱包行为。
非托管钱包的定义与范围
非托管钱包是一种软件或硬件系统,其中控制区块链资产的私钥仅在用户控制的基础设施上生成和存储。钱包可以连接到远程节点以读取链状态和广播已签名交易,但绝不能将私钥或助记词传输到任何服务器。这将其与托管钱包区分开来,在托管钱包中,交易所或平台代表用户持有密钥。
本文侧重于技术机制:密钥派生、本地签名、RPC 交互和验证。它不推荐特定的钱包品牌或比较消费产品。在将钱包连接到网络时选择端点,请使用 RPC Assistant,它提供针对提供商和网络的简短直接建议。
- 非托管:用户持有密钥;签名在本地进行。
- 托管:平台持有密钥;用户向服务进行身份验证。
- 混合模型(MPC、多签)如果没有任何单一第三方可以单方面移动资金,仍属于非托管。
实现的前提条件与假设
以下示例假设 Node.js 18+ 和 Python 3.10+ 可用,并且您可以访问 EVM 兼容网络的 RPC 端点。将 RPC_URL 替换为您的提供商的端点。您还需要一个测试私钥;切勿在开发中使用控制真实资金的密钥。代码使用知名库:JavaScript 的 ethers 和 Python 的 web3.py。
这些示例有意保持最小化,以说明签名边界。生产钱包会增加安全密钥存储、用户确认流程、交易模拟和硬件隔离。
npm install ethers
pip install web3密钥管理模型:助记词、派生路径与存储
大多数非托管钱包使用分层确定性(HD)钱包结构。单个助记词(通常为 12 或 24 个单词)生成主私钥,子密钥沿派生路径(如以太坊的 m/44'/60'/0'/0/0)派生。助记词是最终的恢复秘密;任何获得它的人都可以重建所有派生密钥并签署交易。
钱包必须以抵抗提取的方式存储助记词或私钥。常见方法包括加密密钥库(例如 Web3 Secret Storage)、操作系统钥匙串、安全飞地和硬件钱包,其中密钥永远不会进入通用内存。关键属性是签名发生在可信边界内,并且密钥永远不会被序列化到网络请求中。
- 助记词 = 主秘密;离线备份。
- 派生路径决定控制哪些地址。
- 加密密钥库增加密码层,但其强度仅取决于密码。
- 硬件钱包将密钥保存在专用安全元件中。
非托管钱包中的交易生命周期
当用户发起操作时,交易开始。钱包向 RPC 端点查询当前 nonce、gas 价格和链 ID,构造未签名交易对象,并呈现以供确认。批准后,钱包使用私钥在本地对交易哈希进行签名。然后,已签名的原始交易通过 eth_sendRawTransaction 发送到 RPC 端点。节点将其广播到网络;钱包不需要持有区块链的副本。
这种分离是根本性的:RPC 提供商只看到已签名交易和公共地址,永远看不到私钥。恶意或受损的 RPC 端点可以审查或延迟交易,但无法伪造签名或窃取资金。
const { ethers } = require('ethers');
async function signAndSend() {
const provider = new ethers.JsonRpcProvider('RPC_URL');
const wallet = new ethers.Wallet('PRIVATE_KEY', provider);
const tx = {
to: '0xRecipientAddress',
value: ethers.parseEther('0.01'),
nonce: await provider.getTransactionCount(wallet.address),
gasLimit: 21000,
gasPrice: await provider.getFeeData().then(f => f.gasPrice),
chainId: (await provider.getNetwork()).chainId
};
const signed = await wallet.signTransaction(tx);
const response = await provider.broadcastTransaction(signed);
console.log('Transaction hash:', response.hash);
}
signAndSend().catch(console.error);可运行诊断:使用测试密钥验证本地签名
以下 Python 脚本演示了签名可以完全离线执行。它从测试私钥创建钱包,签署交易,并从签名中恢复发送者地址,而无需联系任何 RPC 端点。如果恢复的地址与钱包地址匹配,则签名边界完好无损。
在隔离环境中运行此脚本。此处使用的私钥是众所周知的测试密钥;切勿将其用于真实资产。
from web3 import Web3
from eth_account import Account
# Well-known test private key (do not use for real funds)
private_key = '0x4c0883a69102937d6231471b5dbb6204fe5129617082792ae468d01a3f362318'
acct = Account.from_key(private_key)
# Build an unsigned transaction
tx = {
'nonce': 0,
'gasPrice': Web3.to_wei('10', 'gwei'),
'gas': 21000,
'to': '0x000000000000000000000000000000000000dEaD',
'value': Web3.to_wei('0.001', 'ether'),
'chainId': 1
}
signed = acct.sign_transaction(tx)
recovered = Account.recover_transaction(signed.raw_transaction)
print('Wallet address:', acct.address)
print('Recovered address:', recovered)
assert recovered == acct.address, 'Signing boundary compromised'
print('Local signing verified. No RPC call made.')预期验证结果与解释
当诊断成功运行时,它会打印钱包地址和恢复的地址,两者必须相同。脚本中没有任何网络调用,这证实签名不依赖于 RPC 提供商。如果地址不同,则签名库或密钥派生配置错误;在继续之前进行调查。
对于完整的端到端测试,使用 RPC 端点将已签名交易广播到测试网,并确认其包含在区块中。下表概述了验证阶段以及每个阶段证明的内容。
- 阶段 1:离线签名和恢复 — 证明密钥隔离。
- 阶段 2:广播到测试网 — 证明 RPC 兼容性。
- 阶段 3:链上确认 — 证明网络接受。
结果表:验证清单
在测试非托管钱包实现时,使用下表记录结果。不要编造值;填写您自己环境中观察到的结果。
| 检查项 | 方法 | 预期结果 | 观察结果 |
|---|---|---|---|
| 密钥从未离开客户端 | 签名期间进行网络捕获 | 没有出站请求包含私钥 | |
| 签名恢复 | 离线恢复脚本 | 恢复的地址等于钱包地址 | |
| RPC 广播 | 将已签名交易发送到测试网 | 返回交易哈希 | |
| 确认 | 轮询 eth_getTransactionReceipt | 收据状态 = 0x1 | |
| Nonce 管理 | 查询 eth_getTransactionCount | Nonce 正确递增 |
排查常见的非托管钱包故障
即使架构正确,也经常出现几个问题。如果账户余额不足以支付价值加 gas,交易可能会因 insufficient funds 被拒绝;这是链状态问题,不是签名失败。nonce too low 错误表示存在具有相同 nonce 的待处理交易;使用 pending 区块标签通过 eth_getTransactionCount 查询待处理 nonce。如果 RPC 端点返回 method not found,提供商可能不支持所需的 JSON-RPC 方法;切换到兼容的端点。
签名验证失败通常源于链 ID 不匹配或 EIP-1559 与遗留交易格式不匹配。确保已签名交易中的 chainId 与网络匹配。对于硬件钱包,确认设备已解锁并选择了正确的派生路径。
- 资金不足:检查余额和 gas 估算。
- Nonce 太低:使用待处理 nonce 或等待确认。
- 链 ID 不匹配:验证网络配置。
- RPC 方法不支持:使用具有完整方法覆盖的提供商。
权衡:热钱包、冷存储与操作风险
非托管钱包将责任转移给用户。热钱包(连接到互联网的软件)提供便利,但使密钥暴露于恶意软件和网络钓鱼。冷钱包(硬件或气隙)减少在线攻击面,但使交易工作流复杂化。多签和 MPC 钱包在多个参与方或设备之间分散信任,消除了单点故障,但代价是协调开销。
没有普遍正确的选择;合适的模型取决于资产价值、交易频率和威胁模型。对于高价值持有,硬件隔离和助记词备份的地理冗余是标准做法。对于频繁的小额交易,具有严格操作卫生的热钱包可能是可接受的。
后续步骤:与基础设施集成并衡量可靠性
一旦验证了本地签名,将钱包连接到可靠的 RPC 基础设施。OnFinality 在许多网络上提供托管 RPC 端点;查看支持的网络和 API 服务选项。对于高吞吐量或延迟敏感的应用,考虑专用节点。定价详情可用于容量规划。
为了衡量可靠性,运行一个脚本,定期查询 eth_blockNumber 并在定义的时间窗口内记录延迟和错误率。使用相同的方法比较提供商。对于具体的端点建议,请咨询 RPC Assistant,而不是依赖通用列表。
- 查看支持的网络:/en/networks
- 探索 API 服务层级:/en/api-service
- 比较专用节点选项:/en/dedicated-node
- 查看 RPC 定价:/en/pricing/rpc
- 了解更多 RPC 基础知识:/en/learn