Zcash RPC 回归测试指南:深入理解 qa/ 目录下的 pull-tester 与 rpc-tests 体系
2026/9/18 14:08:45 网站建设 项目流程

Zcash RPC 回归测试指南:深入理解 qa/ 目录下的 pull-tester 与 rpc-tests 体系

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

Zcash(zcashd)在 qa/ 目录下维护了一套完整的 RPC 回归测试体系,用于在每次 Pull Request 合并前自动化验证节点、钱包与 P2P 协议行为。本文以 qa/README.md 为主线,结合 qa/pull-tester/rpc-tests.py、qa/rpc-tests/test_framework 等源码,系统讲解测试依赖安装、单测/批量/全量运行方式、并行调度参数、cache/缓存机制,以及如何基于测试框架编写新的回归测试,帮助你在本地完整复现 Zcash 的 CI 回归验证流程。

一、测试体系概览:pull-tester 与 rpc-tests 的分工

Zcash 仓库的测试代码分为两个紧密协作的目录:

  • qa/pull-tester/:包含测试调度器 rpc-tests.py 以及由configure生成的配置模板 tests_config.ini.in。它的职责是读取构建配置、汇总测试脚本列表、按并行度调度子进程、汇总通过率并生成 RPC 覆盖率报告。
  • qa/rpc-tests/:存放每一个独立的测试脚本(.py)以及供所有脚本复用的测试框架 test_framework/。每个脚本通过继承框架基类BitcoinTestFramework编写,最终以独立子进程方式被 pull-tester 调用。

根据 qa/README.md,仓库对每个 Pull Request 都会执行完整的构建并通过回归测试套件验证;你也可以在本地运行全部测试或只运行其中某一个。二者是"调度器 + 用例集"的关系:rpc-tests.py通过子进程逐个调用qa/rpc-tests/下的脚本,并将未识别的命令行参数原样转发给测试脚本(见 rpc-tests.py 的模块注释)。

二、环境准备:安装测试依赖

运行测试前需要安装以下 Python 库(回归测试通过 JSON-RPC 驱动真实zcashd进程,因此需要额外的网络协议支持):

  • zmq(pyzmq):供 ZMQ 推送类测试(如zmq_test.py)使用;
  • base58:用于地址与序列化数据的 Base58 编解码。

Unix(Ubuntu / Debian 系发行版):

sudo apt-get install python3-zmq python3-base58

OS X:

pip3 install pyzmq base58

需要说明的是,ZMQ 测试只有在节点启用 ZMQ 支持(--enable-zmq)时才会被调度执行。若本机未安装zmqPython 库,运行rpc-tests.py会直接报错并提示"import zmqfailed. Use--nozmqto run without the ZMQ tests",此时可用--nozmq参数跳过 ZMQ 用例(见 rpc-tests.py)。

三、运行测试:从单测到全量回归

make rpc-tests是官方推荐入口。在 Makefile.am 中,该目标定义为:

rpc-tests: $(BITCOIND_BIN) qa/pull-tester/rpc-tests.py $(RPC_TEST)

它依赖zcashd可执行文件构建完成,保证被测二进制与源码一致。这也是 qa/README.md 特别强调的一点:直接调用qa/pull-tester/rpc-tests.py虽然也能运行,但不会确保zcashd与最近的代码改动保持同步。

3.1 运行单个测试

RPC_TEST=<testname> make rpc-tests

例如:

RPC_TEST=wallet make rpc-tests RPC_TEST=wallet_z_sendmany make rpc-tests

3.2 运行任意组合

RPC_TEST="<testname1> <testname2> <testname3> ..." make rpc-tests

例如同时验证钱包与区块两个维度:

RPC_TEST="wallet.py blockchain.py" make rpc-tests

调度器对传入的脚本名做了宽容处理:接受带或不带.py后缀的写法,只要脚本名存在于其内部的ALL_SCRIPTS注册表中即会被选中(见 rpc-tests.py)。若指定的名字不在注册表中,则会打印 "No valid test scripts specified" 提示并退出。

3.3 运行完整回归套件

make rpc-tests

不带RPC_TEST时,调度器会依次运行:SERIAL_SCRIPTS(串行用例)→FLAKY_SCRIPTS(偶发失败用例)→BASE_SCRIPTS(基础用例),并在启用 ZMQ 时追加ZMQ_SCRIPTS。这套默认集合覆盖了钱包、挖矿、mempool、P2P 拒绝规则、网络升级激活等主要功能面(见 rpc-tests.py)。

3.4 运行扩展套件(含耗时较长的用例)

RPC_TEST="--extended" make rpc-tests

--extended会在基础套件之上追加EXTENDED_SCRIPTS,其中包括pruning.pygetblocktemplate_longpoll.pyrpcbind_test.pyhardforkdetection.pyinvalidateblock.pymaxuploadtarget.py等常规 CI 不执行的用例(见 rpc-tests.py)。这些用例运行时间更长,适合本地深度验证。

四、调度器参数详解:控制并行、覆盖率与单测行为

rpc-tests.py是一个完整的 argparse 程序(见 rpc-tests.py),它自己解析一批"调度级"参数,其余参数原样透传给每个测试脚本。

4.1 调度级参数

参数简写默认值说明
--jobs=n-j4并行运行的测试脚本数,默认 4 个并发
--coverage关闭生成 RPC 接口基础覆盖率报告
--extended关闭在基础套件上追加扩展用例
--exclude=a,b-x以逗号分隔、不带.py后缀地排除某些用例
--nozmq关闭显式跳过 ZMQ 测试(当未安装 pyzmq 时必需)
--deterministic-d关闭让输出更接近确定性,便于多次运行结果对比
--machines/--rpcgroup-m/-r-1将用例分片到多台机器并行执行(需成对使用,-r必须小于-m
--force-f关闭在默认禁用 RPC 测试的平台(如 Windows)上强制运行

其中--machines--rpcgroup的校验逻辑见 rpc-tests.py:两者必须同时提供,且-r索引须小于-m机器数,调度器会按"向上取整的均匀分片"把测试列表拆给每台机器。

4.2 透传给单个测试脚本的参数

qa/README.md 列出了作用于"每次单独测试运行"的选项,其实际解析位置在 test_framework.py 的BitcoinTestFramework.main()中:

-h, --help 显示帮助并退出 --nocleanup 测试结束或出错时保留 zcashd 进程与 test.* 数据目录 --noshutdown 测试执行完毕后不停止 zcashd --srcdir=SRCDIR 包含 zcashd/zcash-cli 的源码目录(默认:../../src) --tmpdir=TMPDIR 数据目录的根目录(默认由 tempfile 生成,前缀 test) --tracerpc 打印测试过程中发起的全部 RPC 调用 --coveragedir=COVERAGEDIR 把被测试覆盖到的 RPC 命令写入该目录

补充几个源码层面的细节:

  • --tracerpc通过logging.basicConfig(level=logging.DEBUG)打开authproxy的调试日志,从而输出每一条 RPC 请求(见 test_framework.py);
  • 每个测试脚本还会额外获得--portseed=<n>,用于在并行运行时为不同测试分配互不冲突的 RPC/P2P 端口号(见 rpc-tests.py)。端口分配规则在 util.py 中定义:节点数上限MAX_NODES = 8,端口下限PORT_MIN = 11000,每个协议各保留 5000 个端口;
  • 框架还隐藏了一个--cachedir选项,默认指向qa/cache,用于缓存预生成的测试数据目录(见 test_framework.py)。

4.3 覆盖率报告

追加--coverage后,调度器会在临时目录初始化覆盖率数据(RPCCoverage),每个测试脚本把执行过的 RPC 命令写入coverage.*文件,最终与zcash-cli help导出的完整命令清单rpc_interface.txt做差集,输出"未被任何测试触达的 RPC 命令"清单(见 rpc-tests.py)。若所有命令都被覆盖,则会打印 "All RPC commands covered."。

4.4 调试输出

设置环境变量可开启额外的调试输出:

PYTHON_DEBUG=1 qa/pull-tester/rpc-tests.py wallet

PYTHON_DEBUG=1时,调度器会以非确定模式逐行打印测试进度点(见 rpc-tests.py),方便观察长耗时用例的执行节奏。

五、缓存机制:200 区块的共享测试基座

qa/README.md 说明了回归测试的高效复用设计:

第一次运行回归测试时,会生成一条 200 区块的-regtest区块链,以及四个节点的钱包,并保存在cache/目录中。每个节点的钱包里包含来自 25 个成熟区块的矿工补贴(25×10=250 ZEC)。

从源码可以还原这条机制的完整实现链:

  1. 当并行运行多个用例(len(test_list) > 1 and jobs > 1)时,调度器会先调用 create_cache.py 预生成缓存(见 rpc-tests.py)。该脚本通过继承BitcoinTestFramework但设置num_nodes = 0、空跑run_test()的方式,只完成区块链与钱包的初始化;
  2. 每个测试脚本在setup_chain()阶段通过initialize_chain()cache/下的区块链与钱包复制到自己的临时目录,作为初始测试状态(见 test_framework.py);
  3. 框架默认cache_behavior = 'current',表示"使用当前分支生成的缓存";ComparisonTestFramework则使用'clean',即不依赖共享缓存、每次从零开始,确保 P2P 对比测试的纯净性(见 test_framework.py)。

这套"复制而非重建"的策略让数百个测试用例共享同一条链的初始状态,避免了每个用例重复挖 200 个区块的开销。

5.1 缓存损坏后的恢复

如果测试环境进入坏状态(例如残留的僵尸zcashd占用了端口、缓存链数据损坏),qa/README.md 给出的恢复手段是:

rm -rf cache killall zcashd

删除cache/后,下一次运行会自动重新生成 200 区块的缓存与钱包;killall zcashd则清理掉可能残留的节点进程。另外,调度器在启动时会基于当前时间戳生成一个伪随机端口偏移(portseed_offset),以便"跳过"僵尸节点可能占用的端口段(见 rpc-tests.py),减少偶发端口冲突。

六、测试脚本的组织:串行、易碎与基础分类

调度器把测试脚本按运行特性分为四类(见 rpc-tests.py):

  • SERIAL_SCRIPTS:必须串行执行的用例,因为其涉及的屏蔽交易花费(shielded spends)会占满所有 CPU 核心,并行会拖垮整体吞吐。当前包括mergetoaddress_sapling.pymergetoaddress_ua_nu5.pymergetoaddress_ua_sapling.pywallet_shieldingcoinbase.py。调度器遇到串行脚本时会立即中断并行添加(见 rpc-tests.py);
  • FLAKY_SCRIPTS:已知偶发失败但尚未定位根因的用例,当前为mempool_nu_activation.pymempool_packages.py
  • BASE_SCRIPTS:基础回归套件,按运行时长从长到短排序(<5m<2m<60s<30s),长用例排在前以便并行调度时整体时间最短。其中包含wallet.pysprout_sapling_migration.pyturnstile.pyfinalsaplingroot.pyfinalorchardroot.pywallet_orchard.pyp2p-fullblocktest.pynuparams.pyfeature_zip244_blockcommitments.pyshielded_balance_accounting_coinbase.py等 120+ 个用例;
  • EXTENDED_SCRIPTS:CI 不执行、仅在--extended时追加的深度用例,如pruning.pygetblocktemplate_longpoll.pyrpcbind_test.pyforknotify.pyhardforkdetection.pyreceivedby.pymaxblocksinflight.pymaxuploadtarget.pyp2p-acceptblock.pywallet_db_flush.py等。

BASE_SCRIPTS中还有一类特殊的带参数条目,例如'txn_doublespend.py --mineblock',表明同一脚本可携带不同参数被调度多次,这要求脚本本身支持命令行参数分支。

七、编写测试:基于 test_framework 的两种范式

qa/README.md 鼓励为新增或既有功能编写测试,并指引读者继续阅读 qa/rpc-tests/ 获取框架细节。qa/rpc-tests/README.md 进一步给出了框架组件的功能地图:

模块用途
test_framework.pyRPC 回归测试的基类(BitcoinTestFramework
util.py通用工具函数(节点启动、区块/内存池同步、端口分配等)
mininode.pyP2P 连接与网络消息对象的底层支持
comptool.py对比式(comparison-tool 风格)P2P 测试框架
script.py交易脚本操作工具(源自 python-bitcoinlib)
blockstore.py磁盘落盘的区块与交易存储
key.py基于 OpenSSL EC_Key 的密钥封装(源自 python-bitcoinlib)
bignum.py供 script.py 使用的大数辅助
blocktools.py构造区块与交易的辅助函数

此外,框架目录还包含 Zcash 特有的模块:equihash.py(Equihash 工作证明)、zip244.py(区块承诺)、zip317.py(费用规则)、flyclient.py(FlyClient 轻客户端)以及 authproxy.py(JSON-RPC 客户端封装)。

7.1 标准 RPC 测试(BitcoinTestFramework)

绝大多数钱包与节点测试采用这种范式:继承BitcoinTestFramework,实现run_test(),框架自动完成"建链 → 启动 4 节点 → 连接成链形网络 → 执行用例 → 停止并清理"的完整生命周期。框架默认启动 4 个节点并按0-1-2-3顺序连接;setup_network()还支持split=True把网络拆成0/12/3两个阵营,用于测试链分叉与重组(见 test_framework.py)。

7.2 P2P 测试(Mininode 与 Comptool)

Mininode范式用于"自由形式"的协议级测试:测试进程内有一个专用线程处理与zcashd的所有网络通信(基于 Pythonasyncore),另一个线程承载测试逻辑。NodeConn负责建立连接,派生自NodeConnCB的回调类会收到感兴趣的事件——注意派生类的__init__中必须调用self.create_callback_map()来建立 P2P 消息与回调函数的映射。同一个回调处理器可以复用到多个NodeConn,所有连接创建完毕后调用NetworkThread.start()启动网络线程,P2P 测试中同样可以直接使用 RPC 调用。典型示例见 p2p-acceptblock.py 与 maxblocksinflight.py。

Comptool范式用于"对比式"测试:将被测zcashd与一个或多个参照节点(--refbinary指定参照二进制,--testbinary指定被测二进制)的行为进行对比,或与预期结果对比。要点包括:

  • num_nodes决定启动的节点数;单节点时用--testbinary更换被测二进制,多节点时--refbinary作用于第 2 个及之后的节点;
  • 实现生成器函数get_tests(),不断yieldTestInstance
  • 每个TestInstance[object, outcome, hash]三元组列表构成:objectCBlock/CTransaction/CBlockHeader(后者用于让测试器按需投递完整头链,支持乱序投递区块);outcomeTrue/False/NoneNone表示比较所有被测节点是否对最优链达成一致);hash为可选的最优链尖期望哈希;
  • 辅助开关sync_every_blockFalse时一次inv全部区块、只校验最后一个;True时逐块同步校验)与sync_every_transaction(类比前者,None结果时还会跨节点对比整个内存池内容)。

Comptool 的典型示例见 invalidblockrequest.py 与 p2p-fullblocktest.py。

八、运行前提与注意事项

  • 构建配置:RPC 测试要求钱包、工具、守护进程三个组件全部启用。configure时若未启用(对应--enable-wallet--with-utils--with-daemon),tests_config.ini.in 中的ENABLE_WALLETENABLE_UTILSENABLE_BITCOIND会被注释掉,rpc-tests.py会打印 "RPC tests require wallet support" 类提示并直接退出(见 rpc-tests.py);
  • 平台限制:Windows 上 RPC 测试默认禁用,需--force强制执行(见 rpc-tests.py);
  • 并行度:默认--jobs=4,可根据机器核数与负载调整;串行脚本不受--jobs影响,始终单独执行;
  • 测试状态隔离:每个测试脚本使用--portseed派生独立端口、复制缓存链到独立tmpdir,互不干扰;退出码0表示全部通过,1表示存在失败用例(见 rpc-tests.py)。

九、小结

Zcash 的回归测试体系以 qa/pull-tester/rpc-tests.py 为调度中枢、以 qa/rpc-tests/ 下的 120+ 测试脚本为用例集、以 test_framework 为公共底座,配合cache/200 区块缓存与端口种子机制,实现了"一次构建、并行复用、全量回归"的高效验证闭环。无论你是想在本地跑通make rpc-tests、排查某个钱包用例的偶发失败,还是打算为新的网络升级或 RPC 接口补充回归用例,沿着"安装依赖 → 单测复现 → 全量回归 → 阅读框架 → 编写用例"这条路径即可快速上手。

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

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

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

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

立即咨询