工作量证明验证
每一个 Proof of Architect 代币都是通过不断挖取 nonce,直到其 keccak-256 哈希具有足够的前导零位而产生的。获胜哈希会成为代币种子,因此这份工作事后完全可验证。本页说明了精确的数学、难度公式以及一个真实的完整示例。参考合约(Arc):0x3E20bb7be2C46f94Cab78d340D3F79Afc2a9Fed4。
1. 原像与哈希
被哈希的值是一个打包的 104 字节字符串——三个整数和两个地址,严格按此顺序排列,字段之间没有填充:
work = keccak256(
abi.encodePacked(
uint256 chainId, // 32 bytes, big-endian
address contract, // 20 bytes
address miner, // 20 bytes
uint256 nonce // 32 bytes, big-endian
)
)
// 32 + 20 + 20 + 32 = 104 bytes
// 104 < 136 = the Keccak-256 rate block, so one hash pass- chainId 在 Arc 上为 5042;nonce 是一个完整的 uint256(大端序),而不是一个小计数器。
- 地址是原始的 20 字节(没有校验和大小写,原像内部也没有 0x 前缀)。
- 该哈希是 Keccak-256(以太坊变体),而非 NIST SHA3-256。
2. 有效性规则
当一个 nonce 的 work 值严格低于该钱包的难度目标时,它就是有效的(v3.4 使用分数目标;requiredMilli 可以落在整数比特之间):
valid <=> uint256(work) < targetFor(miner) // targetFor is derived from requiredMilli (milli-bits = thousandths of a bit): // requiredMilli = (baseBits + 2*epochIndex + loadAdjust + streakBits)*1000 - stakingDiscountMilli (floored at baseBits*1000, capped at 250 bits) // requiredBits(miner) = ceil(requiredMilli/1000) is the display value only. // Expected number of attempts ~= 2^(requiredMilli/1000).
前导零位(而非字节)意味着以 0x00 开头的哈希至少有 8 个有效位,0x0000 至少 16 个有效位,依此类推。30 比特的难度平均需要大约十亿次哈希。
3. 难度公式
requiredMilli(miner) =
max( baseBits * 1000,
( baseBits + 2 * epochIndex + loadAdjust + streakBits ) * 1000
- stakingDiscountMilli(miner) ) // capped at 250 bits
targetFor(miner) = 2^(256 - intPart) / 2^(tenths/10) // intPart=tenths split from requiredMilli| 术语 | 含义 | 单位 |
|---|---|---|
| baseBits | 该部署的波次 1 基础难度(当前部署为 30 比特)。 | bits |
| 2 * epochIndex | 每波 +2 比特;每一波约难 4 倍。链上上报的、从 1 开始的波次是 epochIndex + 1(以 1,000 次付费铸造为一个周期)。 | bits |
| loadAdjust | 负载调节器,0..64 比特,每 5 次铸造微调一次,以 25 秒/次铸造为目标节奏(过快时 +2 比特,过慢时 -1 比特;收紧与放宽之间有 ±20% 的死区)。 | bits |
| streakBits | 按钱包的连续挖矿:在同一钱包处于冷却期内时,每多挖一次 +2 比特(冷却时间 = 按连续等级固定为 5–25 分钟,上限 25 分钟)。冷却期结束后重置。 | bits |
| stakingDiscountMilli(miner) | 由质押金库提供的 PoW 折扣(最多 6 比特,下限为 baseBits)——见下文。 | bits |
质押折扣(当前核心)
持有者可以在质押金库中锁定一个 Architector 以降低个人难度。折扣取该钱包所有活跃质押中的最大值,上限为 6 比特,且结果的下限为 baseBits:
| 层级 | 锁定期 | 折扣(毫比特) |
|---|---|---|
| 0 | 0 天(灵活) | 0(无折扣) |
| 1 | 7 天 | 500 = 0.5 bits |
| 2 | 30 天 | 1500 = 1.5 bits |
| 3 | 90 天 | 3000 = 3 bits |
| 4 | 180 天 | 4500 = 4.5 bits |
| 5 | 365 天 | 6000 = 6 bits |
当前部署已将质押金库注册为一个模块,因此折扣是实时生效的:在质押金库中锁定一个 Architector,你所需的比特数最多可减少 6,下限为 baseBits。
4. 完整示例(参考向量)
一个自包含、可复现的向量:该系列的第一次主网铸造(token #1)。其获胜 nonce 是针对实时 v3.4 核心挖出的,并由浏览器矿工、GPU 矿工和 MCP 服务器逐字节交叉验证。以下全部是公开的链上数据——可用任意 keccak 库重新计算该哈希。
为什么是 31 比特:该哈希以 0x00 00 00 01 开头——三个零字节(24 比特)再加上 0x01 = 00000001(另外 7 个前导零)= 31。波次 1 的全新钱包面临 30 比特的基础难度(在调节器和连续挖矿调整之前),因此这份工作通过了门槛。要对任何真实的铸造进行重新验证,可将其 miner/nonce 传给 verify_nonce,或用任意 keccak 库直接重新计算该哈希。
5. 如何验证
使用 MCP 工具 verify_nonce
远程 MCP 服务器暴露了 verify_nonce(miner, nonce)。它在本地重新计算 work(它不信任 RPC 给出的 PoW 判定),并将其与实时从合约读取的 targetFor(miner) 进行比对(valid ⟺ uint256(work) < target)。miner 是一个带 0x 前缀的地址;nonce 是一个十进制的 uint256 字符串。
tool : verify_nonce
arguments : { "miner": "0x…", "nonce": "14825046255063054065" }
returns : {
"miner": "0x…",
"nonce": "14825046255063054065",
"work": "0x…",
"target": "0x…",
"valid": false,
"note": "valid is checked against the CURRENT target…"
}配套工具:required_bits(miner) 用于查询当前难度,get_token(tokenId) 用于查询代币所有者、种子和 nonce。端点与客户端配置见 /docs/agent-access。
使用站点 API 和链上读取
元数据端点 GET /api/meta/{id} 提供某个代币推导出的属性和稀有度,但不提供原始种子。要独立验证,请从合约读取下面这三个值(或通过 MCP 的 get_token 工具),并在本地重新计算:
read seedOf(id) -> bytes32 // the winning work, stored on mint read nonceOf(id) -> uint256 read ownerOf(id) -> address // the miner at mint time read mintBlockOf(id) -> uint64 // 0 for claim tokens recompute work = keccak256(chainId, contract, owner, nonce) assert work == seedOf(id) // byte-for-byte display = mintBlockOf == 0 ? seedOf : keccak256(seedOf ‖ blockhash(mintBlockOf + 2)) // the display seed is what drives traits/art (post-inclusion entropy)
元数据读取示例:
curl -sS https://proofofarchitect.builders/api/meta/1
一个快速的免费难度探测:调用 eth_estimateGas(针对 mint(),使用全新的 nonce)。它会以 BelowFloor(uint8 got, uint8 need)(选择器 0xfcf93064)回滚,并在没有任何交易的情况下揭示当前难度。
6. 为什么稀有度是确定性的
没有服务器端随机数,也没有预言机。原始代币种子就是获胜的 work 哈希本身(seedOf(tokenId) = work,免费领取则是领取哈希)。驱动属性的 ART 种子是展示种子:keccak256(seedOf ‖ blockhash(mintBlockOf + 2)),用于铸造和锻造的代币(领取类代币保留 seedOf)。区块哈希是一个未来的区块——只在铸造落地后才固定——因此没有人(甚至矿工也无法)能为得到一个有利的种子而挖取。Arc 的 PREVRANDAO 为零在这里无关紧要。
Architector 的属性是展示种子的纯函数:每个槽位通过确定性的加权拒绝采样抽取,消耗 keccak256(seed ‖ uint8 slotIndex ‖ uint16 counter),并按十六个大端序 uint16 字读取。稀有度则是所得属性集的信息量:-Σ log2(count(value) / totalTokens),再映射到一个层级(标准、显著、稀有、史诗、神话)。
结果:同一个展示种子总是产生同一张卡和相同的稀有度,任何人都可以从链上状态重新计算两者。由于展示种子是包含后的,属性和稀有度无法在铸造前预览(此前的铸造前预览已移除)。分数和层级通过 GET /api/meta/{id} 在 rarity 下提供。