K. HPChain: TFLOP/s, Redefined.¶
在 AI 时代,浮点算力( FLOPs )是唯一的硬通货。
注: 本题不计分,仅作为娱乐题目。
题目背景¶
在去年的画板题中,小鸣成功在画板上留下了属于自己浓墨重彩的一笔,并获得了纪念 T 恤。小鸣因此深受鼓舞,决定投身于更具挑战性的区块链技术—— HPChain 。
HPChain 是一个去中心化的算力调度与交易账本。在 HPChain 中,每个参与者都是算力供应商。通过解决基于 SM3d 算法的计算难题,供应商可以证明其设备的实时计算效能,从而获得可交易的算力单位 TFLOPS 。算力提供商通过将自己的算力证明在区块链上,从而可以均衡调度不同地区、不同时间的算力,达到东数西算、南水北调的效果。
题目描述¶
给定一个包含 100 笔交易( 1 笔 Coinbase 交易 + 99 笔普通交易)的交易池,你的任务是构建一个有效的区块,使得该区块头的 SM3d 哈希值小于或等于给定的目标值。
区块头结构 (80 Bytes)¶
| 偏移量 | 长度 ( Bytes ) | 描述 |
|---|---|---|
| 0 | 4 | 版本号 |
| 4 | 32 | 前一区块哈希 |
| 36 | 32 | Merkle Root |
| 68 | 4 | 时间戳 |
| 72 | 4 | 难度位 ( nBits ) |
| 76 | 4 | 随机数 ( Nonce ) |
核心逻辑¶
你需要:
- 构建 Merkle Root :从给定的 100 笔交易中构建 Merkle 树。
- Coinbase 交易必须是第一笔交易
- 其余 99 笔普通交易可以 任意重新排序
- 所有 100 笔交易都 必须包含 在区块中
- Merkle 树构建使用 双重 SHA256 算法(
SHA256(SHA256(data))) - 选择时间戳 :时间戳必须满足:
- 大于等于
problem.dat中指定的基准时间戳 - 小于等于提交时间 + 2 小时
- 寻找 Nonce :不断尝试修改 Nonce 字段,计算:
Result = SM3(SM3(Header))
当满足 $ Result \le Target $ 时,即代表你成功捕捉到了一个有效的算力块。
Merkle Root 构建规则¶
Merkle 树的构建遵循:
- 对每笔交易计算双重 SHA256 :
txid = SHA256(SHA256(tx_data)) - 将所有 txid 作为叶子节点
- 两两配对计算父节点:
parent = SHA256(SHA256(left || right)) - 如果节点数为奇数,最后一个节点与自己配对
- 重复直到得到根节点( Merkle Root )
注意 :
- 交易哈希( txid )计算使用 SHA256d
- Merkle 树内部节点计算使用 SHA256d
- 只有最终的区块头哈希使用 SM3d
输入格式¶
程序从 /tmp/problem.dat 读取二进制格式的问题数据:
[ 4 bytes ] version ( little-endian uint32 )
[ 32 bytes ] previous_block_hash
[ 4 bytes ] nbits ( little-endian uint32 )
[ 4 bytes ] base_timestamp ( little-endian uint32 )
[ 4 bytes ] num_transactions ( little-endian uint32, always 100 )
[ for each transaction: ]
[ 4 bytes ] tx_length ( little-endian uint32 )
[ tx_length bytes ] transaction_data
说明 :
version: 区块版本号previous_block_hash: 前一个区块的哈希值( 32 字节)nbits: 难度目标的压缩表示( 4 字节)base_timestamp: 基准时间戳,你选择的时间戳必须 ≥ 此值num_transactions: 交易数量(固定为 100 )- 每笔交易以长度前缀的方式存储
nBits 到 Target 的转换¶
nBits 是难度目标的压缩表示,转换公式:
exponent = ( nbits >> 24 ) & 0xFF
mantissa = nbits & 0x00FFFFFF
target = mantissa * 256 ^ ( exponent - 3 )
输出格式¶
输出到标准输出,共五行:
- 第一行:找到的符合条件的Nonce 值(十六进制, 8 位)
- 第二行:使用的Merkle Root (十六进制, 64 位)
- 第三行:使用的Timestamp (十进制)
- 第四行:计算出的完整Block Hash 值(十六进制, 64 位)
- 第五行 :交易顺序(空格分隔的交易索引,第一个必须是 0 表示 coinbase )
你可以在 Handout 中找到基准程序、示例输入与输出日志。
运行环境与评分¶
- 硬件: Kunpeng 920F (4 核心)
- 编译器:
g++ -O3 -fopenmp -pthread -std=c++17 -march=native -o hpchain hpchain.cpp -lssl -lcrypto - 评分:
- 正确性:
- 必须包含所有 100 笔交易
- Coinbase 交易必须在第一位
- Merkle Root 计算正确
- 时间戳在有效范围内
- 区块哈希满足难度目标
- 性能: 寻找有效区块的耗时越短,排名越高
- Judger 会给出 9 个测例,分别有不同的难度值及目标优化时间。
提示与优化方向¶
- 并行计算: 充分利用pthread或OpenMP ,将 Nonce 空间划分给不同核心
- Merkle Root 优化:
- 预先计算所有可能的 Merkle Root (通过重排交易)
- 或者固定一个交易顺序,专注于 Nonce 搜索
- SM3d 算法优化:
- 区块头前 64 字节( version + prev_hash + merkle_root 前半部分)可以预计算
- 考虑内联汇编优化关键路径
- Kunpeng 处理器支持硬件 SM3 加速
- 时间戳策略:
- 时间戳的变化会改变区块头,提供额外的搜索空间
- 可以在 Nonce 空间耗尽时更新时间戳
- 交易重排序:
- 虽然可以重排交易来改变 Merkle Root ,但计算成本较高
- 建议优先优化 Nonce 搜索速度