← 文档 · 收藏

工作量证明验证

每一个 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

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

层级锁定期折扣(毫比特)
00 天(灵活)0(无折扣)
17 天500 = 0.5 bits
230 天1500 = 1.5 bits
390 天3000 = 3 bits
4180 天4500 = 4.5 bits
5365 天6000 = 6 bits

当前部署已将质押金库注册为一个模块,因此折扣是实时生效的:在质押金库中锁定一个 Architector,你所需的比特数最多可减少 6,下限为 baseBits。

4. 完整示例(参考向量)

一个自包含、可复现的向量:该系列的第一次主网铸造(token #1)。其获胜 nonce 是针对实时 v3.4 核心挖出的,并由浏览器矿工、GPU 矿工和 MCP 服务器逐字节交叉验证。以下全部是公开的链上数据——可用任意 keccak 库重新计算该哈希。

chainId5042
合约(v3.4 主网)0x3E20bb7be2C46f94Cab78d340D3F79Afc2a9Fed4
tokenId1
miner0x6Cd98C52dBB7771E5112e0d4a959F03eF10796dc
nonce14825046255063054065
work(keccak256 原像)0x00000001092bd7ef7b35d8f8f7980a783616fc870ad9b0f89168d82b46b66d12
leadingZeroBits(work)31
targetFor(miner)分数目标(work < target)
validtrue(work < target)

为什么是 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 下提供。

相关:代理接入 · 统计数据集 · 文档索引 · GitBook