BrokerHub

BrokerHub
agsd0. BrokerHub 可以用来干什么?
BrokerHub一个由中山大学 HuangLab 开发的区块链协议验证平台,名为 BlockEmulator。
简单来说,它的用途是帮助研究人员或学生快速“模拟”和“验证”新的区块链技术,特别是“分片(Sharding)”和“共识协议”。它不是一个用来挖矿赚钱的工具,而是一个科研实验工具。
0.1它可以帮你做这些事:
- 模拟区块链运行:
它可以在一台电脑(或多台)上模拟出一整条分片区块链网络,包含多个分片、多个节点。 - 验证“跨分片”机制:
它内置了两种主流的跨分片技术(BrokerChain 的 Broker 机制和 Monoxide 的 Relay 机制),你可以用它来测试不同分片间怎么处理交易。 - 验证“共识”算法:
它支持 PBFT(拜占庭容错)等共识协议,你可以修改代码来测试自己写的新共识算法效果如何。 - 跑实验、出数据:
它会自动记录 TPS(吞吐量)、延迟等核心指标,并输出成 CSV 文件。写论文或做研究时,可以直接用这些数据画图。 - 支持智能合约:
它包含了一个 VM 模块,可以在模拟链上跑 Solidity 智能合约。
总结:如果你在做区块链底层技术的研究(比如想改进分片效率、设计新共识),这个项目就是你的“测试沙盒”,让你不必从零写一条区块链就能验证你的想法。
1. 核心参数说明
项目的核心参数集中在 BrokerHub/params/global_config.go 文件中。
1.1关键参数配置
| 参数名 | 默认值 | 含义/作用 | 更新建议 |
|---|---|---|---|
| Block_Interval | 1000 |
出块间隔 (ms) 每隔多少毫秒产生一个新区块 |
想让出块更快就改小,模拟高延迟环境可改大 |
| MaxBlockSize_global | 500000 |
区块最大容量 一个区块里最多能装多少笔交易 |
限制吞吐量上限的参数之一 |
| InjectSpeed | 5000 |
交易注入速度 (TPS) 模拟器每秒向网络发送多少笔交易 |
最重要的负载参数 想测极限性能就把这个调大,看系统能不能撑住 |
| TotalDataSize | 500000 |
总交易数量 整个实验一共跑多少笔交易后停止 |
控制实验时长。如果跑太久,可以改小这个值 |
| BatchSize | 5000 |
批处理大小 Supervisor 每次读取并发送多少笔交易 |
最好比 InjectSpeed 稍微大一点,保证发送顺畅 |
| ShardNum | 4 |
分片数量 整个网络被切分成几个片 |
验证分片扩展性的核心参数 |
| NodesInShard | 4 |
分片内节点数 每个分片里有多少个节点参与共识 |
节点越多,共识(PBFT)通常越慢 |
| BrokerNum | 1 |
Broker 数量 辅助跨分片的中间人节点数量 |
仅在 broker 模式下生效 |
| DatWrite_path | "./result/" |
数据输出路径 实验结果 CSV 存哪儿 |
一般不用改 |
1.2如何修改参数
- 打开配置文件
- 编辑
global_config.go文件 - 找到对应的变量值直接修改数字
- 编辑
修改代码后需要重新编译
2. 如何运行BrokerHub
在 Windows 上大致分两步:
- 编译
- 运行脚本
2.1编译
1 | go build -o blockEmulator_Windows_Precompile.exe ./main.go |
2.2运行
1 | .\bat_shardNum=3_NodeNum=4_mod=Broker_b2e.bat |
直接执行 Windows 启动脚本(会自动启动 3 个分片、每分片 4 个节点并写入配置)。
执行过程如下。
3. BrokerHub 项目实验无法自动终止问题的排查与修复
3.1问题描述
在运行 BrokerHub(BVM + Brokerchain 实验平台)时,执行启动脚本 bat_shardNum=3_NodeNum=4_mod=Broker_b2e.bat 后,实验进程无法自动终止,Supervisor 日志中 epoch 计数持续递增(已超过 500),result 目录始终未生成。
3.2系统停止机制分析
通过阅读源码,梳理出系统的正常关闭流程如下:
supervisor.go 中 SupervisorTxHandling() 的执行顺序为:
1 | MsgSendingControl() 返回 |
其中 StopSignal 机制(见 supervisorStopModule.go)要求连续收到 stopThreshold 个空区块消息后才判定实验结束。任何非空区块都会将计数器重置为 0。
3.3逐步排查过程
3.3.1 排查一:supervisor.go 中的调试代码
在 supervisor.go 发现无限循环:
1 | add |
程序在这里无限等待,即进入死循环,每秒 sleep 一次。
如果不注释掉注释,Supervisor 在这里会一直卡住,不会继续往下执行(不会发送 stop 信号,也不会关闭和写入结果文件)。
3.3.2 排查二:MsgSendingControl() 死循环(根因)
启动脚本使用 -m 4,对应 CommitteeMethod[4] = "Broker_b2e",实际加载的实现为 committee_brokerhub.go 中的 BrokerhubCommitteeMod.MsgSendingControl()。
对比能正常终止的 BrokerCommitteeMod.MsgSendingControl()(-m 2),后者从 CSV 文件读取交易,达到 TotalDataSize 后 break 退出。而 BrokerhubCommitteeMod 的实现包含两个无退出条件的死循环:
1 | // 死循环 1:无限生成随机交易 |
由于 MsgSendingControl() 永远不返回,SupervisorTxHandling() 中后续的停止逻辑永远无法执行。值得注意的是,代码中已定义了 simulation_param.endedEpoch = 86 字段,且在其他方法中存在对该字段的判断(第 473、806 行),但 MsgSendingControl() 中未引用此退出条件。
修复措施:在 MsgSendingControl() 中引入 endedEpoch 退出机制。核心改动如下:
1 | done := make(chan struct{}) |
通过 channel 信号在两个循环间协调退出,确保 epoch 达到上限后 MsgSendingControl() 正常返回。
3.4验证
修复后重新编译运行,程序在约 86 个 epoch(约 3 分钟)后自动终止,result 目录正常生成,包含 Supervisor 测量指标 CSV 与 Broker 余额/收益数据。
3.5结论
本次问题的直接原因是 BrokerhubCommitteeMod.MsgSendingControl() 缺少退出条件,属于功能性缺陷。排查过程中虽也发现了调试代码残留的问题并予以修正。修复思路是复用已有的 endedEpoch 字段,以最小改动实现循环退出,保持与原有架构的一致性。
4. 极端参数压力测试学习法
对global_config.go中参数进行极端取值。来观察系统行为,便于理解复杂系统。
1 | package params |
终端输出循环不停。
4.1StopSignal 停止机制
supervisorStopModule.go 中的 StopSignal 维护一个计数器 stopGap,判定逻辑如下:
- 每当 Supervisor 收到一个
BlockInfoMsg且BlockBodyLength == 0(空块),stopGap++ - 每当收到一个
BlockBodyLength > 0(非空块),stopGap归零 - 当
stopGap >= stopThreshold(值为2 × ShardNum = 6)时,判定实验结束
这意味着:必须连续收到 6 个来自各分片的空区块上报,中间不能被任何一个非空区块打断。
4.2区块的完整生命周期
要理解 StopSignal 何时能被满足,需要追踪从交易注入到区块上报的完整链路:
1 | Supervisor (MsgSendingControl) |
4.3Broker 机制产生的交易放大效应
当 Supervisor 的 dealTxByBroker() 处理一笔跨分片交易时,会产生交易乘法效应:
1 | 原始跨片交易 (Sender@Shard0 → Recipient@Shard1) |
一笔原始交易至少衍生出 2-3 笔链上交易,而这些衍生交易的确认(createConfirm)又会在 HandleBlockInfo 回调中进一步触发 handleBrokerType1Mes → txSending(tx1s) 和 handleBrokerType2Mes → txSending(tx2s),形成交易注入 → 上链 → 回调确认 → 再注入的闭环。
4.4极端参数如何破坏停止条件
当前参数为 Block_Interval = 1,MaxBlockSize_global = 1,InjectSpeed = 1。分析其所导致的时序关系:
4.4.1 出块速率远超交易消化速率
1 | Block_Interval = 1ms → 每个分片每毫秒尝试出一个块 |
注意:虽然 MaxBlockSize_global = 1,但 blockchain.go 第 1129 行 中 PackTxs 的参数被硬编码为 50000,因此 MaxBlockSize_global 这个参数实际上不起作用。每次出块时会把交易池中的所有交易一次性打包。
4.4.2 Broker 衍生交易形成持续注入流
每个 epoch(每 2 秒),Supervisor 生成一批随机交易。其中跨片交易经 Broker 拆分后,产生 Tx1、Tx2、AllocatedTx 注入到不同分片。这些交易上链后,Supervisor 在 HandleBlockInfo 中收到区块上报,触发 createConfirm 回调,回调中又会通过 txSending 向分片注入新的交易(Tx2 的确认触发等)。
时序如下:
1 | t=0s :epoch 1 注入原始交易 → 衍生 Tx1、Tx2 注入各分片 |
关键问题:由于出块间隔仅 1ms,系统在 epoch 间隙期间并非空闲——之前 epoch 的衍生交易的确认回调会不断产生新交易,这些交易以极高频率(1ms 一个块)被打包上报。3 个分片交替上报非空块,使得 stopGap 计数器在到达 6 之前就被频繁重置。
4.4.3 三分片交替出块的竞态效应
3 个分片独立出块,各自的出块时机不同步。即使某个分片的交易池已空,其他分片可能仍有衍生交易在处理:
1 | 时间线: --|------|------|------|------|------|---> |
三个分片的非空块在时间轴上交错出现,使得连续空块窗口始终无法维持到 6 个。
4.5合理参数为何能正常停止
当 Block_Interval = 1000(1 秒)时:
- 每个分片每秒只出一个块,给系统充足时间消化所有衍生交易
- 一个 epoch 的所有交易(原始 + 衍生 + 确认)在几个块内就能全部处理完
- epoch 间隙(2 秒)内足够出 2 轮空块,3 个分片各出 2 个空块 = 6 个空块上报
stopGap能够顺利累积到阈值 6,触发正常关闭
4.6结论
StopSignal 的设计前提是:交易注入有限、出块间隔合理、衍生交易能在若干轮出块内被完全消化。极端参数(1ms 出块)打破了这一前提——Broker 的交易放大效应 + 确认回调的循环注入 + 多分片交替出块,使得系统中始终存在零星的非空块,stopGap 计数器永远无法连续累积到阈值。
三个分片的非空块在时间轴上交错出现,使得连续空块窗口始终无法维持到 6 个。
4.7合理参数为何能正常停止
当 Block_Interval = 1000(1 秒)时:
- 每个分片每秒只出一个块,给系统充足时间消化所有衍生交易
- 一个 epoch 的所有交易(原始 + 衍生 + 确认)在几个块内就能全部处理完
- epoch 间隙(2 秒)内足够出 2 轮空块,3 个分片各出 2 个空块 = 6 个空块上报
stopGap能够顺利累积到阈值 6,触发正常关闭
4.8结论
StopSignal 的设计前提是:交易注入有限、出块间隔合理、衍生交易能在若干轮出块内被完全消化。极端参数(1ms 出块)打破了这一前提——Broker 的交易放大效应 + 确认回调的循环注入 + 多分片交替出块,使得系统中始终存在零星的非空块,stopGap 计数器永远无法连续累积到阈值。








