Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
集成与开发阅读约 12 分钟

非托管钱包架构:密钥管理、交易签名与验证

一份关于非托管钱包设计的技术指南,涵盖密钥派生、本地签名、RPC 交互以及自托管行为的可复现验证。

TL;DR

非托管钱包是一种系统,用户独自控制授权交易的私钥;任何第三方都无法移动或冻结资金。本文解释了底层的密钥管理模型,展示了如何使用标准库和 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_getTransactionCountNonce 正确递增

排查常见的非托管钱包故障

即使架构正确,也经常出现几个问题。如果账户余额不足以支付价值加 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

永远不用担心基础设施

OnFinality 消除了 DevOps 的繁重工作,让您能够更聪明、更快地构建。

开始