Zcash 2.1.2-rc1 版本解析:Heartwood 网络升级、Sapling 查看密钥与 z_viewtransaction 深度指南
2026/9/18 16:17:52 网站建设 项目流程

Zcash 2.1.2-rc1 版本解析:Heartwood 网络升级、Sapling 查看密钥与 z_viewtransaction 深度指南

【免费下载链接】zcashZcash - Internet Money项目地址: https://gitcode.com/GitHub_Trending/zc/zcash

zcash(Zcash)v2.1.2-rc1 是部署Heartwood 网络升级(Network Upgrade 3)的准备版本,同时为钱包引入Sapling 扩展全量查看密钥支持与全新的z_viewtransaction屏蔽交易查看 RPC。本文以官方发布说明(doc/release-notes/release-notes-2.1.2-rc1.md)为骨架,结合本仓库源码,系统讲解 Heartwood 升级内容、mineraddress挖矿配置、查看密钥导入导出、时间调整机制移除、z_viewtransaction使用、old-consensus-branch-id错误处理、-txexpirynotify通知以及构建系统变化,帮助节点运维者、矿池开发者和钱包开发者理解该版本的全部技术要点与实操方法。

一、版本总览与 Heartwood 网络升级

1.1 本次发布的核心内容

v2.1.2-rc1 的主要工作是完成 Heartwood 网络升级的代码准备,并打包进本次发布。Heartwood 将部署以下两个 ZIP 提案:

  • ZIP 213:Shielded Coinbase——允许矿工将区块奖励(coinbase)直接挖到 Sapling 屏蔽地址,实现"屏蔽化铸币"。
  • ZIP 221:FlyClient - Consensus-Layer Changes——在共识层引入历史树(history tree)承诺,为轻客户端(FlyClient)提供高效验证区块的能力。

此外,该版本还包含多项钱包与 RPC 功能增强:

  • Sapling 查看密钥(ZIP 32 定义的 Sapling 扩展全量查看密钥)支持;
  • 新 RPCz_viewtransaction,可查看钱包内交易的屏蔽交易细节;
  • 完全移除时间调整机制与-maxtimeadjustment=选项;
  • 对过期交易的通知支持-txexpirynotify
  • 拒绝交易时的old-consensus-branch-id明确错误消息;
  • z_importkey/z_importviewingkey返回密钥类型与地址;
  • getblock/getblockhash支持负高度;
  • 新 RPCgetexperimentalfeatures

1.2 网络升级部署机制与激活高度

Heartwood 的部署遵循 ZIP 250 描述的流程。在发布时,Heartwood 在testnet上的激活高度尚未确定(发布说明中以 XXXXXX 占位),mainnet 的激活高度同样未指定。因此:

  • 对于节点运维者:v2.1.2 在 mainnet 上即使未来 Heartwood 激活后,行为仍与之前的 pre-Heartwood 版本类似。要跟随 mainnet 上的 Heartwood 升级,必须从 2.1.2 版本升级到之后的正式版本(例如 2.1.2 之后的 Heartwood 激活版本)。
  • 对于开发与测试:可以在regtest 模式下通过配置选项-nuparams=f5b9230b:HEIGHT在指定高度激活 Heartwood。其中f5b9230b是 Heartwood 的共识分支 ID(Consensus Branch ID)。这一机制在 src/init.cpp 中有实现,init阶段会解析-nuparams参数并将其写入网络升级部署表。

在测试代码 qa/rpc-tests/feature_zip221.py 中可以看到典型的 regtest 配置用法:

nuparams(BLOSSOM_BRANCH_ID, 1), nuparams(HEARTWOOD_BRANCH_ID, 10), nuparams(CANOPY_BRANCH_ID, 32), nuparams(NU5_BRANCH_ID, 35),

这表示在 regtest 模式下,可以在第 10 个区块高度激活 Heartwood,便于自动化测试。

二、Mining to Sapling addresses:屏蔽化 Coinbase 实操

2.1 配置步骤

ZIP 213 的 Shielded Coinbase 允许区块奖励直接输出到 Sapling 地址。矿工与矿池若要在 Heartwood testnet 上测试该功能,按以下步骤操作:

  1. z_getnewaddress生成一个新的 Sapling 地址;
  2. zcash.conf中添加配置项mineraddress=SAPLING_ADDRESS
  3. 重启zcashd节点;
  4. 调用getblocktemplate,此时返回的 coinbase 交易将包含一个屏蔽矿工输出。

2.2 重要注意事项

发布说明特别强调:mineraddress只有在 Heartwood 网络升级激活之后才能设置为 Sapling 地址。如果在 Heartwood 激活之前设置 Sapling 地址,getblocktemplate将返回无法被挖出的区块模板(因为此前共识规则不允许屏蔽 coinbase 输出)。

2.3 源码中的mineraddress实现

从源码可以看出该选项的完整实现链路:

  • 选项定义与帮助文本在 src/init.cpp:
    -mineraddress=<addr> Send mined coins to a specific single address
  • 启动时对地址进行解析校验,src/init.cpp 要求地址必须能被解析为 Zcash 地址(Sapling、透明 P2PKH 或包含有效接收者的统一地址),否则报错:
    Invalid address for -mineraddress=<addr>: Unable to parse '%s' as a Zcash address.
  • init还会将-mineraddress的挖矿目标写入挖矿逻辑,见 src/init.cpp。若无-mineraddress且钱包可用,则回退到钱包地址。
  • 挖矿侧的实现位于 src/rpc/mining.cpp,getblocktemplate在组装区块时会检查-mineraddress(src/rpc/mining.cpp),并缓存屏蔽 coinbase(src/rpc/mining.cpp)。若没有可用的矿工地址,getblocktemplate会返回错误No miner address available (getblocktemplate requires a wallet or -mineraddress)(src/rpc/mining.cpp)。

RPC 测试 qa/rpc-tests/feature_zip221.py 以及 src/gtest/test_miner.cpp 中包含了 Shielded Coinbase 的回归测试,验证了屏蔽 coinbase 可以被挖出并花费到透明地址。

三、Sapling 查看密钥支持

3.1 查看密钥概念

本版本将 ZIP 32 定义的Sapling 扩展全量查看密钥(Sapling Extended Full Viewing Keys)支持加入钱包。导入 Sapling 查看密钥后,节点会跟踪与这些密钥关联的 Sapling 地址的所有发送与接收交易,实现"只读"监控,而无需持有花费密钥。

关于查看密钥能查看哪些信息、具备何种保证,发布说明指向 ZIP 310 进行详细说明。

3.2 相关 RPC 操作

  • z_exportviewingkey:获取节点钱包中某个屏蔽地址的查看密钥。Sapling 地址的查看密钥以zxviews开头(testnet 为zxviewtestsapling)。
  • z_importviewingkey:将查看密钥导入另一个节点。导入的 Sapling 查看密钥会持久化存储在钱包数据库中,重启后仍然保留。
  • z_getbalance:显示与导入查看密钥关联的 Sapling 地址余额。
  • z_gettotalbalance:当includeWatchonly参数设为true时,将包含查看密钥关联的余额。
  • z_listreceivedbyaddress等查看屏蔽交易信息的 RPC,会返回与导入查看密钥关联的 Sapling 地址的信息。

RPC 注册位置见 src/rpc/common.h,实现在 src/wallet/rpcwallet.cpp。钱包密钥库中对应支持AddSaplingFullViewingKey等操作(见 src/wallet/keystore.cpp),并在钱包数据库中持久化导入的扩展查看密钥。

3.3z_importkey/z_importviewingkey返回值增强

从本版本开始,z_importkeyz_importviewingkey会返回导入的密钥类型(sproutsapling)以及对应的支付地址,方便钱包应用确认导入结果。

四、移除时间调整与-maxtimeadjustment=

4.1 背景:timejacking 攻击

在 v2.1.1-1 之前,zcashd会根据前 200 个连接对等节点发送的时间的中位数,将本地时间最多调整 70 分钟。该机制本质上不安全:攻击者通过建立多个连接,可以在 ±70 分钟窗口内有效控制节点的时间——这被称为timejacking 攻击

在 v2.1.1-1 安全版本中,除了其他缓解措施外,最大时间调整被默认设置为零,实际上禁用了时间调整;但当时仍提供了-maxtimeadjustment=选项来覆盖此默认值。

4.2 本版本的变化

为简化代码,时间调整代码已完全移除,-maxtimeadjustment=选项也随之删除。节点运维者应确保本地时间设置得足够准确。

若节点时间与其对等节点存在显著差异,仍会记录警告,并在启用指标屏幕(metrics screen)时显示。相关改动包括Remove uses of GetTimeOffset()Update GetAdjustedTime() to GetTime()等提交,均可在发布说明的 Changelog 中查证。

五、新 RPCz_viewtransaction:查看屏蔽交易细节

5.1 填补的功能空白

在之前的zcashd版本中:

  • z_listreceivedbyaddress返回地址收到的所有 note;
  • z_listunspent返回未花费的 note(可按地址过滤);
  • 没有任何 RPC 直接返回花费(spends)细节,也没有与透明交易的gettransaction等价的方法。

z_viewtransaction正是为填补这一空白而生。

5.2 功能与返回字段

给定钱包中的一笔交易 ID,z_viewtransaction会解密该交易,并返回所有可解密的新增与花费 note 的详细屏蔽信息:

  • 每个 note 所属的地址;
  • 以十进制 ZEC 和 zatoshis 表示的金额;
  • 每个花费 note 的来源交易 ID(txidPrev);
  • 每个新增 note 的outgoing标志:若输出不属于钱包中的地址则为true
  • 每个新增 note 的memoStr字段:当 memo 字段包含有效 UTF-8 字符串时返回其文本形式。

信息的展示范围覆盖z_listaddresses中出现的所有地址,包括通过z_importviewingkey导入的 watch-only 地址,以及持有花费密钥的地址(无论由z_getnewaddress生成还是由z_importkey导入)。

5.3 RPC 完整签名与返回结构

从 src/wallet/rpcwallet.cpp 可以看到该 RPC 的完整定义:

z_viewtransaction "txid" Get detailed shielded information about in-wallet transaction <txid> Arguments: 1. "txid" (string, required) The transaction id Result: { "txid" : "transactionid", "spends" : [ { "pool" : "sprout|sapling|orchard", // 屏蔽价值池类型 "type" : "sprout|sapling|orchard", // 已废弃的旧属性 "js" : n, // (sprout) vJoinSplit 中 JSDescription 的索引 "jsSpend" : n, // (sprout) JSDescription 中 spend 的索引 "spend" : n, // (sapling) vShieldedSpend 中 spend 的索引 "action" : n, // (orchard) orchard bundle 中 action 的索引 "txidPrev" : "transactionid", // 该 note 创建时所在交易的 ID "jsPrev" : n, // (sprout) vJoinSplit 中 JSDescription 的索引 "jsOutputPrev" : n, // (sprout) JSDescription 中 output 的索引 "outputPrev" : n, // (sapling) vShieldedOutput 中 output 的索引 "actionPrev" : n, // (orchard) orchard bundle 中 action 的索引 "address" : "zcashaddress", "value" : x.xxx, // 金额,单位 ZEC "valueZat" : xxxx // 金额,单位 zatoshis } ], "outputs" : [ { "pool" : "sprout|sapling|orchard", "type" : "sprout|sapling|orchard", // 已废弃的旧属性 "js" : n, // (sprout) JSDescription 索引 "jsOutput" : n, // (sprout) JSDescription 中 output 的索引 "output" : n, // (sapling) vShieldedOutput 中 output 的索引 "action" : n, // (orchard) orchard bundle 中 action 的索引 "address" : "zcashaddress", // 找零输出不包含此字段 "outgoing" : true|false, // 输出不属于钱包地址则为 true "walletInternal" : true|false, // 是否找零输出 "value" : x.xxx, "valueZat" : xxxx, "memo" : "hexmemo", // memo 字段的十六进制表示 "memoStr" : "memo" // 可选的 UTF-8 文本 memo(有效时存在) } ] }

调用示例:

# CLI 方式 zcash-cli z_viewtransaction "1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d" # RPC 方式 curl --data-binary '{"jsonrpc":"1.0","id":"curltest","method":"z_viewtransaction","params":["1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d"]}' -H 'content-type: text/plain;' http://127.0.0.1:8232/

5.4 源码实现要点

z_viewtransaction的实现在 src/wallet/rpcwallet.cpp,它会:

  1. 校验交易必须存在于钱包中(pwalletMain->mapWallet),否则抛出Invalid or non-wallet transaction id
  2. 加锁cs_mainpwalletMain->cs_wallet保证一致性;
  3. 分别构建spendsoutputs数组,使用 OutgoingViewingKeys 恢复非钱包的 Sapling 输出(对应 changelog 中 "RPC: Use OutgoingViewingKeys to recover non-wallet Sapling outputs");
  4. 通过 utfcpp 依赖对 memo 进行 UTF-8 校验并生成memoStr(对应 "depends: Add utfcpp to dependencies" 与 "RPC: Display valid UTF-8 memos in z_viewtransaction")。

RPC 测试 qa/rpc-tests/wallet_listreceived.py 中检查了z_viewtransaction的输出(对应 changelog 中 "test: Check z_viewtransaction output in wallet_listreceived RPC test")。

六、old-consensus-branch-id:更明确的交易拒绝错误

6.1 问题背景

Zcash 的网络升级过程包含多个保护用户的特性,其中之一是共识分支 ID(Consensus Branch ID),它防止网络升级激活后创建的交易在其他链上被重放——这被称为双向重放保护(two-way replay protection),也是加密生态对"硬分叉"式变更的核心要求。

然而,重放保护的实现方式有一个缺点:交易被拒绝时,无法直接区分"针对不同分支"和"签名无效"。过去,当用户没有升级钱包软件、或钱包缺少对新网络升级共识分支 ID 的支持时,创建交易产生的错误消息非常不直观,对透明交易尤其晦涩。

6.2 本版本的改进

从本版本开始,zcashd节点会对无效的透明与 Sprout 签名使用最近一次网络升级之前的共识分支 ID 重新验证。如果此时签名变为有效,交易将以错误消息old-consensus-branch-id被拒绝。钱包服务提供商可以专门处理该错误,向用户提示"需要升级钱包软件"。

6.3 源码实现

该逻辑在 src/main.cpp 的ContextualCheckShieldedInputs()中实现:先用当前分支 ID 计算签名哈希,若验证失败,再使用PrevEpochBranchId()得到的前一时期分支 ID 重新计算并验证;若第二次验证成功,则返回:

old-consensus-branch-id (Expected %s, found %s)

其中%s分别填充当前分支 ID 与前一分支 ID 的十六进制表示(src/main.cpp)。透明交易签名的类似回退检查位于 src/main.cpp。相关 gtest 见 src/gtest/test_checktransaction.cpp 与 src/gtest/test_validation.cpp。

6.4 钱包软件如何获取最新分支 ID

钱包软件可以从(已升级的)zcashd节点自动获取最新的共识分支 ID:调用getblockchaininfo,读取 JSON 输出中的{'consensus': {'nextblock': BRANCH_ID, ...}, ...}

七、-txexpirynotify:过期交易通知

7.1 功能与配置

新配置选项-txexpirynotify=<cmd>会在 mempool 中的交易过期时执行指定命令,可用于通知外部系统交易已过期,其工作方式与-blocknotify(链尖变化时通知)类似。帮助文本见 src/init.cpp:

-txexpirynotify=<cmd> Execute command when transaction expires (%s in cmd is replaced by transaction id)

7.2 实现机制

回调实现位于 src/init.cpp 的TxExpiryNotifyCallback():读取-txexpirynotify参数值,将其中的%s替换为过期交易的 ID(十六进制),然后在独立线程中执行命令:

static void TxExpiryNotifyCallback(const uint256& txid) { std::string strCmd = GetArg("-txexpirynotify", ""); boost::replace_all(strCmd, "%s", txid.GetHex()); boost::thread t(runCommand, strCmd); // thread runs free }

这意味着配置示例可以写为:

# zcash.conf txexpirynotify=/path/to/script.sh %s

当任意 mempool 交易过期时,script.sh将以过期交易 ID 作为参数被执行。

八、其他 RPC 与构建系统变化

8.1 RPC 变更汇总

  • z_importkey/z_importviewingkey:现在返回导入密钥的类型(sproutsapling)与对应支付地址。
  • getblock/getblockhash负高度:允许使用负高度从链尖向前选择区块,-1对应主链上最后一个已知有效区块。实现见 src/rpc/blockchain.cpp,帮助文本明确 "If negative then -1 is the last known valid block"(src/rpc/blockchain.cpp)。getblockhash同样支持(src/rpc/blockchain.cpp)。
  • getexperimentalfeatures:返回已启用的实验性功能列表,无参数。实现见 src/rpc/misc.cpp,注册在control类别(src/rpc/misc.cpp)。底层功能集合来自 src/experimental_features.cpp,包括developerencryptwalletdevelopersetpoolsizezeropaymentdisclosureinsightexplorerlightwalletd等;未开启-experimentalfeatures时直接设置这些实验选项会在 init 阶段报错(src/experimental_features.cpp)。
zcash-cli getexperimentalfeatures # 例如返回:["insightexplorer"]

8.2 构建系统变化

  • zcutil/build.sh--enable-lcov--disable-tests--disable-mining标志已移除。需要这些标志时,通过CONFIGURE_FLAGS环境变量传递。例如启用覆盖率检测(从而使make cov生效):

    CONFIGURE_FLAGS="--enable-lcov --disable-hardening" ./zcutil/build.sh
  • 构建系统默认不再输出详细(verbose)日志,可通过./zcutil/build.sh V=1重新启用详细输出。

  • 其他值得注意的构建改动:新增--with-sanitizersconfigure 选项、--enable-debug的默认值优化、硬编码/fPIE选项拆分、Rust 工具链调整(依赖系统中固定 Rust 目标平台)等,详见 Changelog。

九、运维与升级注意事项

9.1 升级路径

  • 当前 mainnet 上 Heartwood 尚未激活,v2.1.2 的行为与之前的 pre-Heartwood 版本类似;要跟随 mainnet 的 Heartwood 升级,必须在 Heartwood 正式激活前升级到后续版本
  • 若要在 testnet 或 regtest 上提前验证 Heartwood 特性(屏蔽 coinbase、ZIP 221 历史树),分别使用 testnet 激活高度(关注官方公告)或 regtest 的-nuparams=f5b9230b:HEIGHT

9.2 配置检查清单

配置项用途注意事项
mineraddress=SAPLING_ADDRESS将区块奖励挖到 Sapling 地址仅在 Heartwood 激活后设置 Sapling 地址
-nuparams=f5b9230b:HEIGHTregtest 下指定高度激活 Heartwood仅 regtest 模式有效
-txexpirynotify=<cmd>交易过期时执行命令%s会被替换为交易 ID
-experimentalfeatures及子选项启用实验功能不开启全局标志时设置子选项会启动失败

9.3 时间同步建议

由于时间调整机制已完全移除,节点运维者应通过 NTP 等方式保证本地时间准确;节点时间与对等节点显著不一致时,仅会记录警告并在指标屏幕显示,不再自动调整。

十、Changelog 关键提交索引

发布说明末尾附有完整的 Changelog,按贡献者分类列出本次发布的所有提交。以下是各主题对应的关键提交,便于按需追溯源码:

  • Heartwood / ZIP 213 / ZIP 221Add ZIP 213 consensus rulesAdd support for Sapling addresses in -mineraddressAdd ZIP 221 logic to block indexImplement ZIP 221 consensus rulesconsensus: From Heartwood activation, use Rust Equihash validator
  • 查看密钥SaplingFullViewingKey -> SaplingExtendedFullViewingKey in keystore mapsAdd Sapling ExtFVK support to z_exportviewingkeyStore imported Sapling ExtFVKs in wallet database
  • z_viewtransactionRPC: z_viewtransactionRPC: Use OutgoingViewingKeys to recover non-wallet Sapling outputsdepends: Add utfcpp to dependencies
  • 时间调整移除Remove uses of GetTimeOffset()Replace time adjustment with warning only
  • 重放保护错误消息mempool: Check transparent signatures against the previous network upgradeconsensus: Check JoinSplit signatures against the previous network upgrade
  • 构建系统zcutil/build.sh: Remove lcov and mining flagszcutil/build.sh: Turn off verbosity by default
  • RPC 测试框架:大范围的 Python 2 → Python 3 迁移,涉及qa/rpc-testsqa/rpc-tests/test_framework
# 查看 build.sh 当前支持的构建选项 ./zcutil/build.sh --help # 启用覆盖率检测后构建并运行覆盖率测试 CONFIGURE_FLAGS="--enable-lcov --disable-hardening" ./zcutil/build.sh make cov

结语

v2.1.2-rc1 是 Zcash 走向 Heartwood 网络升级的关键过渡版本:它完成了 ZIP 213 屏蔽 coinbase 与 ZIP 221 FlyClient 共识层变更的代码准备,同时显著增强了钱包的查看能力(Sapling 查看密钥 +z_viewtransaction),并为开发者提供了更友好的错误消息(old-consensus-branch-id)、交易过期通知(-txexpirynotify)和更灵活的构建配置。对于矿池与钱包开发者,该版本的mineraddress、查看密钥导入导出与z_viewtransaction是理解后续 Heartwood/CANOPY 时代 Zcash 屏蔽功能演进的重要基础。

【免费下载链接】zcashZcash - Internet Money项目地址: https://gitcode.com/GitHub_Trending/zc/zcash

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询