# Prevrandao 安全性分析

## 概述

`block.prevrandao`（EIP-4399）是以太坊合并后引入的区块级伪随机数。虽然它为链上随机数提供了一种便捷的方案，但也存在一些安全性考量。本文深入分析 Prevrandao 的安全性及 MemeDice 的防护措施。

***

## 什么是 Prevrandao？

### 技术背景

在以太坊合并（The Merge）之前，`block.difficulty` 表示区块的挖矿难度。合并后，以太坊从 PoW 转为 PoS，`block.difficulty` 字段被重新定义为 `prevrandao`（EIP-4399）。

```
合并前：block.difficulty = 挖矿难度（可预测）
合并后：block.difficulty = prevrandao（伪随机数）
```

### RANDAO 机制

`prevrandao` 的值来自以太坊的 RANDAO 累加器：

```mermaid
graph LR
    A[验证者 1<br/>提交 reveal] --> B[RANDAO 混合]
    C[验证者 2<br/>提交 reveal] --> B
    D[验证者 3<br/>提交 reveal] --> B
    B --> E[prevrandao<br/>下一个区块使用]
    
    style B fill:#4F46E5,color:#fff
    style E fill:#059669,color:#fff
```

每个 epoch 中，被选中的验证者必须提交一个 RANDAO reveal 值，该值与之前的 RANDAO 混合值进行 XOR 运算，产生新的 `prevrandao`。

***

## 安全性分析

### ✅ 对普通用户的安全性

对于普通用户（非验证者），Prevrandao 是安全的：

| 安全属性     | 说明                        |
| -------- | ------------------------- |
| **不可预测** | 普通用户无法预测下一个区块的 prevrandao |
| **不可操纵** | 普通用户无法影响 prevrandao 的值    |
| **可验证**  | 任何人都可以通过区块浏览器验证           |

### ⚠️ 验证者操纵风险

区块验证者（proposer）存在一定的操纵能力，但在ETH主网进行操纵的成本极大：

#### 1. 选择性出块

验证者可以选择 **不提议区块**（放弃出块权），从而影响 RANDAO 的混合结果。

```
正常流程：验证者提议区块 → prevrandao = RANDAO_mix XOR reveal
操纵流程：验证者放弃出块 → prevrandao = 上一个 RANDAO_mix（不变）
```

**代价**：放弃出块意味着放弃该区块的所有奖励（约 0.05 ETH + MEV）。

#### 2. 选择性包含交易

验证者可以选择 **不包含** 某笔下注交易，使其延迟到下一个区块执行。

```
区块 N：验证者看到下注交易 → 计算结果 → 不利 → 不包含该交易
区块 N+1：另一个验证者包含该交易 → 使用不同的 prevrandao
```

**代价**：可能损失交易的 gas 费收入。

#### 3. 操纵的经济分析

| 因素       | 说明                       |
| -------- | ------------------------ |
| **操纵成本** | 放弃出块奖励（\~0.05 ETH + MEV） |
| **操纵收益** | 取决于下注金额                  |
| **操纵概率** | 验证者只有 1 bit 的影响力（出块或不出块） |
| **结论**   | 仅在下注金额远大于出块奖励时才有经济动机     |

> 💡 **实际风险评估**：对于普通金额的下注（< 1 ETH），验证者操纵的经济动机极低。验证者需要放弃约 0.05 ETH 的出块奖励，且只有 1 bit 的影响力（50% 概率改变结果）。

***

## MemeDice 的防护措施

### 1. EOA 限制（`onlyEOA`）

Prevrandao 模式强制要求调用者必须是 **外部账户（EOA）**，不允许合约调用。

```solidity
// 伪代码
modifier onlyEOA() {
    require(msg.sender == tx.origin, "Only EOA");
    _;
}
```

**防护目的**：

* 防止 **闪电贷攻击**：攻击者无法在同一笔交易中借款 → 下注 → 根据结果决定是否回滚
* 防止 **合约预测**：合约无法在调用前读取 `block.prevrandao` 并决定是否下注

### 2. 下注限额

游戏创建者可以设置最大下注金额（`maxBet`），限制单笔下注的风险敞口。

**防护目的**：

* 降低验证者操纵的经济动机
* 限制单笔下注的最大损失

### 3. 资金池锁定

待结算的下注金额会被锁定（`pendingLockedAmount`），确保资金池有足够的代币支付。

### 4. 网络限制

Prevrandao 模式仅在支持 `prevrandao` 的网络上可用：

| 网络          | 支持 Prevrandao | 说明             |
| ----------- | ------------- | -------------- |
| Ethereum 主网 | ✅             | 合并后原生支持        |
| BSC         | ❌             | 不支持，只能用 Oracle |
| Base        | ✅             | L2             |

***

## 与 Oracle 模式的安全性对比

| 安全维度            | Oracle 模式          | Prevrandao 模式 |
| --------------- | ------------------ | ------------- |
| **密码学安全**       | ✅ commit-reveal 保证 | ⚠️ 依赖协议层      |
| **验证者操纵**       | ✅ 不受影响             | ⚠️ 存在理论风险     |
| **闪电贷攻击**       | ✅ 异步结算，无法回滚        | ✅ EOA 限制防护    |
| **Oracle 单点故障** | ⚠️ 依赖 Oracle 服务    | ✅ 不依赖第三方      |
| **超时风险**        | ⚠️ Oracle 不响应需等待   | ✅ 即时结算        |
| **可验证性**        | ✅ commitHash 验证    | ✅ 区块浏览器验证     |

***

## BSC 为什么不支持 Prevrandao？

BSC（BNB Smart Chain）使用 **Parlia 共识机制**（基于 PoSA），与以太坊的 PoS 不同：

* BSC 没有实现 RANDAO 机制
* `block.prevrandao` 在 BSC 上返回的值不具有随机性
* 因此 MemeDice 在 BSC 上只支持 Oracle 模式

***

## 总结

| 结论         | 说明                          |
| ---------- | --------------------------- |
| **普通玩家**   | Prevrandao 模式足够安全，操纵风险极低    |
| **大额玩家**   | 建议使用 Oracle 模式，获得密码学级别的安全保证 |
| **BSC 用户** | 只能使用 Oracle 模式              |
| **追求速度**   | Prevrandao 模式提供即时结算体验       |

> 💡 **建议**：如果你不确定选择哪种模式，默认的 **Oracle 模式** 是最安全的选择。

***

## 延伸阅读

* [EIP-4399: Supplant DIFFICULTY opcode with PREVRANDAO](https://eips.ethereum.org/EIPS/eip-4399)
* [Ethereum RANDAO 机制](https://eth2book.info/capella/part2/building_blocks/randomness/)

***

## 相关链接

* ⬅️ 返回 [技术深度概览](/ji-shu-gai-lan/ji-shu-shen-du-gai-lan.md)
* 🎲 了解 [Oracle vs Prevrandao](/ji-shu-gai-lan/oracle-vs-prevrandao.md)
* 🔒 了解 [游戏安全性](/ji-shu-gai-lan/you-xi-an-quan-xing.md)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.dapp.meme/ji-shu-gai-lan/prevrandao-an-quan-xing-fen-xi.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
