一、内容提要
- 共识算法
- POW
- POS
- DPOS
- PBFT
- P2P
- 协议的介绍
- 协议的过程
文章目录
- 一、内容提要
- 二、共识算法
- [三、P2P 协议](#三、P2P 协议)
-
- [图解 P2P](#图解 P2P)
- [P2P 协议的基本原理](#P2P 协议的基本原理)
-
- [P2P 节点发现与消息传播要点](#P2P 节点发现与消息传播要点)
- [P2P 网络的组织结构](#P2P 网络的组织结构)
- [P2P 协议的应用场景](#P2P 协议的应用场景)
- [P2P 协议的优缺点](#P2P 协议的优缺点)
- 未来趋势与挑战
- 四、总结
- [五、参考资料 & 致谢](#五、参考资料 & 致谢)
二、共识算法
怎么去理解共识算法
多方对某一个提案达成一致的过程叫做共识过程,共识过程需要一些算法机制,比方说 POW 和 POS 等
一个简单的例子,班级里面选择一个班长,如果是老师直接指定,那么是中心化的;如果是通过投票选举出来的,这种事去中心化的,投票的过程其实就是一个共识算法。
为什么区块链非要共识不可?因为账本要在互不信任的节点之间保持一致:谁有权记账、记哪一笔、以哪个版本为准,都必须有大家共同遵守的规则,否则就会出现"同一笔钱花两次"(双花)。评价一个共识算法通常看三件事:安全性 (诚实节点不会确认冲突的账本)、活性 (网络最终能继续出块)、终局性(确认后的区块能否被回滚)。PoW 用算力投票,终局是概率性的;BFT 类算法用消息投票,一旦提交就是确定性终局。下面这张表先建立全局印象,后面逐个展开:
主流共识算法速览
| 算法 | 类型 | 容错模型 | 终局性 | 代表链/项目 |
|---|---|---|---|---|
| PoW | 算力竞争 | 诚实算力占优(防 51% 攻击) | 概率终局,最长链原则 | 比特币 |
| PoS | 质押投票 | 作恶罚没质押(Slashing) | checkpoint 最终化 | 以太坊 |
| DPoS | 委托选举超级节点 | 选举 + PBFT 兜底 | 依实现而定 | EOS、Solana |
| PBFT | 三阶段消息投票 | N = 3f + 1 | 确定性终局 | Hyperledger Fabric 0.6 |
| Tendermint | 两轮投票 + 锁定 | 2/3 以上诚实 | 确定性终局 | CometBFT / Cosmos 生态 |
| HotStuff | 线性通信 BFT | 2/3 以上诚实 | 确定性终局 | Libra/Diem 系 |
提示:Solana 是组合拳------POH 负责排序、DPoS 选出块人、PBFT 负责状态一致,不是单一算法。
共识算法相关的概念
确认位

图:确认位示意------后续区块不断叠加,交易被回滚的概率越来越低
长程攻击

图:长程攻击示意------攻击者试图从远古区块开始重写一条竞争链
区块分叉

图:区块分叉示意------同一高度出现竞争区块,网络需要规则选择主链
POW 共识算法
POW 共识算法主要是用在比特币及其衍生链里面,共识过程如下:
所有的 validator 一起来找一个 nonce 值,使得 Hash(nonce + blockData) < target
- nonce:节点共识过程中需要寻找的值
- target:是挖矿难度值,target 越小,挖矿难度越大
交易先发送到 mempool, 参与共识的节点先将交易打包成区块,开始去计算这个 nonce 值,若找到目标的 nonce 值,使得 Hash(nonce + blockData) < target, 就将区块生成出来,全网广播,其他节点接受到这个区块之后,进行区块验证,验证通过之后落块。

挖矿难度问题
- 在比特币里面,每过 2016 个块,就会进行一次难度调整,按照每 10 分钟出一个块的话,每次调整大约需要两周的时间。
- d i f f c u l t n e w = d i f f c u l t o l d ∗ ( A c t a u l T i m e / T a r g e t T i m e ) diffcult_{new} = diffcult_{old} * (ActaulTime / TargetTime) diffcultnew=diffcultold∗(ActaulTime/TargetTime)
- 出块时间控制 10 分钟左右,保证区块不会发生分叉丢失
为什么难度要动态调整?因为全网算力随时在变:算力涨了不调难度,出块就会越来越快,分叉和通胀都会失控;算力跌了不调难度,网络可能半天出一个块。比特币用"每 2016 个块按实际耗时/目标耗时缩放难度"的反馈机制,把出块节奏钉在 10 分钟左右。还要理解 PoW 的概率终局:你的交易被打包后,后面每多叠一个块,回滚它需要重算的算力就越多,通常等 6 个确认就被认为足够安全------这不是数学上的绝对不可逆,而是经济上"不划算"。
Bitcoin 的总量是 2100 万枚,每隔 21 万个区块会发成一次减半
- 50
- 50 / 2
- 50 / 4
- 50 / 8
- 50 / n
减半公式:50(1/2 + 1/4 + 1/8 + ... + 1/n) = 2100 万枚
比特币挖矿产生一个区块的时候会有两层奖励
- 第一层:来自于比特币的挖矿奖励(区块里面的第一笔交易为挖矿奖励的交易)
- 第二层:正常的交易手续费
下面用一段 Python 代码把「找 nonce」的过程最小化复现出来,帮助理解 Hash(nonce + blockData) < target 到底在算什么:
python
import hashlib
def mine(block_data: str, target_prefix: str, max_nonce: int = 10_000_000) -> int:
"""暴力搜索 nonce,使 sha256(nonce + blockData) 以 target_prefix 个 0 开头。
target_prefix 越大,难度越高(等价于 target 越小)。"""
for nonce in range(max_nonce):
raw = f"{nonce}{block_data}".encode()
digest = hashlib.sha256(raw).hexdigest()
if digest.startswith("0" * target_prefix):
return nonce
raise RuntimeError("在给定范围内没有找到满足条件的 nonce")
if __name__ == "__main__":
data = "block#1000|txs:alice->bob:1BTC"
for difficulty in (2, 3, 4):
nonce = mine(data, difficulty)
print(f"difficulty={difficulty}, nonce={nonce}")
运行后你会发现:难度每加 1,平均尝试次数大约翻 16 倍(十六进制每一位有 16 种取值),这正是比特币难度调整的数学基础。
比特币如何解决分叉问题

在比特币里面,当产生分叉的时候,以最长链为原则
POS 共识算法
使用质押投票的机制完成共识过程的一个共识算法,在共识过程中,若节点存在作恶,就会被惩罚,若节点正常完成共识,就会获得奖励。
- 第一层意思:需要质押一定量的资金
- 第二层意思:需要投票,完成共识过程
- 第三层意思:正常投票(不做恶)就会获得奖励,投票者有投票奖励,出块人有出块的奖励
- 第四层意思:异常投票(作恶)质押的资金就会被罚没有
前提条件是你要参与投票共识,必须要先质押,一般情况下很多质押协议要求最小质押量,要大于最小质押量,才有机会参与网络共识。
PoS 要解决的核心难题是"无利害关系"(nothing-at-stake)问题:PoW 里矿工押注算力,分叉两边只能选一边挖;PoS 里投票不耗电,理论上验证者可以在两条分叉上同时投票两头下注。解决办法就是罚没(Slashing):一旦检测到双重投票等作恶证据,直接扣掉质押金,让作恶有真金白银的成本。以太坊还通过 checkpoint 机制给区块"盖章":过一个检查点变 safe,过两个变 Finalized,Finalized 之后想回滚就要烧掉巨量质押金,经济上几乎不可能。
以太坊的 POS 共识算法
ETH2.0 和 Pectra 升级
从 POW 到 POS 升级是 ETH2.0 最核心的变化,共识算法从 POW 变成 POS
- 在 Pectra 升级之前
- 在 ETH2.0 升级的时候,限定如果要在以太坊上启动一个节点,需要质押 32 个 ETH,小于 32 个 ETH 不能启动这个节点;大于 32 ETH 多出部分不会纳入奖励的计算。
- 在 Pectra 升级之后
- 限定启动一个节点参与 ETH 网络共识最少需要 32 个 ETH,最大可以到 2048 个 ETH,目前正在运行 ETH 版本质押范围为 32-2048 个 ETH
以太坊的项目结构

- 通过 engine_newPayLoad 生成 payload
- 使用 engine_getPayLoad 通过 payload Id 获得生成数据
- 执行 engine_forceUpdate 的方法将 payload 数据组织区块插入到链里面去
LSP
在真实情况中,很多人持有 ETH 都是小于 32 个,有的甚至只有几个 ETH,这些闲散的 ETH 就无法参与整个网络的共识获得奖励。
怎么办:有人做了一个系统,将这些散户 ETH 集中起来,当集中的 ETH 大于等于 32 个,就去启动节点参与网络的共识,参与网络共识会获得奖励,这些奖励一部分被中介拿走,比方说 5%-8%;剩下的再给到散户;我们一起来看看这个产品是怎么做的:

- 第一步:用户质押 ETH,LSP mint 对应权益 token 给到用户
- 第二步:当 LSP 里面的资金大等于 32 ETH 时,链下服务监听到该事件之后,驱动将 LSP 资金充值到信标链合约,当新质押再进来,先将该节点质押的数量补充到 2048; 最新的质押达到 32 ETH 再去启动新的节点。
- 第三步:充值完成值,启动一个信标链节点参与网络的共识出块
- 第四步:出块完成之后,节点会获得奖励,矿池节点进行奖励抽成(节点拿 5-8%),剩余的奖励给到 LSP 产品侧
- 第五步:LSP 产品侧拿到奖励之后,抽成之后(LSP 拿 5-8%),将奖励分发给用户
- 第六步:用户取回质押,需要将权益 token 退回去,合约 burn 权益 token 之后释放 ETH 给到用户
- 第七步:LSP 退出,停掉节点,取回信标链合约资金
LSP(流动性质押协议)本质上做了两件事:一是聚沙成塔 ,把散户不足 32 ETH 的资金凑成整份去跑节点;二是发权益凭证,用户质押后拿到 LST(如 stETH 这类权益 token),凭证可以继续去 DeFi 里使用,质押不再是"死钱"。理解这条链路时抓住一个原则:节点运维和奖励分配分层抽成,用户承担的是协议合约风险与节点罚没风险的传导。
以太坊共识过程细化

第一步:用将交易发送到 geth/reth 的执行客户端里面的 txpool
第二步:信标链通过调用 engine_newPayload 的接口驱动 geth 客户端生成 payload
第三步:信标链通过调用 engine_getPayload 的接口获取 payload 的数据进行共识验证
第四步:信标链通过调用 engine_forceUpdate 方法将 payload 生成区块插入到链中
第五步:当区块确认位到 32 个区块时候,信标链指导 geth 将区块的状态变成 safe
第六步:当区块确认位到 64 个区块时候,信标链指导 geth 将区块的状态变成 Finalized
把上面六步落到代码层面,本质是执行客户端(geth/reth)对外暴露的 Engine API 调用序列,可以用下面的伪代码串起来:
python
# 信标链(共识层)视角的伪代码:一个 slot 内的典型调用顺序
def on_slot_start(slot: int):
# 1. 交易进入执行层 txpool(由用户 RPC 提交,非 Engine API)
# 2. 让执行层基于父区块构造候选 payload
payload_id = engine_new_payload(
parent_hash=chain.head.hash,
payload_attributes={
"timestamp": slot * 12,
"prevRandao": randao_reveal(slot),
"suggestedFeeRecipient": proposer_fee_recipient(slot),
},
)
# 3. 取回 payload 内容,用于在共识层做投票验证
payload = engine_get_payload(payload_id)
if not verify_state_root(payload):
return vote_nil(slot)
# 4. 投票通过后,把 payload 落成区块插入链中
block_hash = engine_forkchoice_updated(
head_block_hash=payload.block_hash,
safe_block_hash=chain.safe.hash,
finalized_block_hash=chain.finalized.hash,
)
# 5/6. 确认位推进时,同步更新 safe / finalized 指针
if confirmations(block_hash) >= 32:
chain.safe = block_hash
if confirmations(block_hash) >= 64:
chain.finalized = block_hash
注意 engine_forkchoice_updated 同时承担了「插入区块」和「推进 safe/finalized 指针」两个职责,这也是以太坊把共识与执行解耦(PoS 合并后)的关键设计。
理解区块的推导流程
- Epoch: 以太坊共识出块的一个周期,在一个周期内,参与区块投票的人是一样的,一个 epoch 含有 32 个 slot
- Slot: 用来装载区块的,每一个 slot 里面包含一个区块,每隔 12s 会出现一个 slot, 如果在一个 slot 期间没有任何交易,就不会出块,这个时候 slot 是空的
- Block: 用来打包交易的,每一个区块都需要放到一个 slot 里面去,区块会有三个状态分别是:Unsafe, Safe 和 Finalized
- CheckPoint: 每隔 32 个 slot 就有一个 checkpoint

- 图中我们以 128 这个点开始去整个图
- 64-96 个 slot 里面区块已经过一个 checkpoint, 过了 32 slot, 这里面区块状态都是 safe
- 0-64 个 slot 里面的区块已经过了两个 checkpoint, 也就是说过了 64个slot,这里面区块状态都是 Finalized
以太坊共识过程中怎么去解决区块分叉问题的

DPOS
DPOS:委托质押协议,超级节点的机制,不是所有都可以参与出块,而是选举一群人具备出块的权限,代表链 EOS,21 个超级节点, Solana, 101 个超级;
DPOS 的工作流程
- 质押 Token: 质押的 Token 越多,具备的权益越大
- 投票选举:所以质押人投票选举出来一小群人来进行网络的出块
- 出块流程:被选举出来人,开始打包,验证和区块出出来
- PBFT 负责区块状态达成一致, 例如: 出块出现分叉,将由 PBFT 共识算法来解决
- DPOS 选择出来节点挂,那么会新选择新的节点出来
Solana 共识 = POH + DPOS + PBFT
- POH:交易的排序,按照一定规则进行交易排序
- DPOS:质押选举出块人,超级节点负责出块
- PBFT:负责区块状态达成一致
PBFT
最早追溯到拜占庭将军问题
PBFT 最早用在区块链里面,应该是 Hyperledger Fabric(IBM 出的联盟链,只有 Hyperledger Fabric 0.6 之前的版本使用了 PBFT, 1.0 之后用户的 kafka + zookeeper )
拜占庭容错算法 N = 3f + 1; n 代表的节点总数, f 代表允许出异常的节点; f = (N -1)/3;
例如我们有 10 个节点,公式会变成如下情况
10 = 3f + 1 ====> f = (10 - 1)/3 = 3; 在 PBFT, 需要有 2/3 以上的节点是正常,这个网络才能正常工作
Hyperledger Fabric 0.6
Hyperledger Fabric 0.6 算法分为三个阶段 pre-prepare, prepare 和 commit
- pre-prepare(view change 过程耗时比较长)
- 客户端将需要共识消息发送到 server, 当网络收到需要共识消息,会进行一次 view change, 选择出一个主节点完成整个共识过程
- prepare
- 主节点收到需要共识消息之后,会全网广播一个 prepare 的一个消息体,其他的副本节点收到消息之后,验证消息的真实性,然后对这个消息进行确认,给主节点回复确认消息。
- commit
- 主节点收到 2/3 以上的节点对消息的确认之后,再广播 commit 的消息,消息确认之后,主节点直接打包生成区块,返回给到客户端。
View change: 选择主节点的过程,如果网络主节点挂了,也会发一次 view change 重新选择主节点。
为什么容错公式是 N = 3f + 1?直觉上,f 个节点可能宕机不回复、另外 f 个节点可能作恶乱回复,剩下 f + 1 个诚实节点必须能推动流程,所以总节点数至少 3f + 1,收集到 2f + 1(约 2/3)票就能保证其中一定有诚实节点。PBFT 的代价是通信复杂度 O(n²):每个阶段大家都要互相广播消息,节点一多网络就被消息淹没,这也是它适合联盟链、不适合上万节点公链的原因。把三阶段画成流程就是:

图:PBFT 从客户端请求到提交出块的三阶段消息流
提示:pre-prepare/prepare 解决"大家看到同一条消息",commit 解决"大家都知道大家看到了",两轮确认缺一不可。
CometBFT
算法简介
CometBFT 采用Tentmint 共识,一种易于理解、基本异步的 BFT 共识算法。该算法遵循一个简单的状态机,如下所示:

上图展示了 Tendermint BFT 共识流程,描述了一个区块从提议(Propose)到最终提交(Commit)的完整过程。Tendermint 共识采用三阶段投票机制(Prevote、Precommit、Commit) 来确保区块最终性。以下是详细解析:
流程分解
- 新高度(New Height)
- 在前一个区块提交后,链进入新的高度(New Height)。
- 提议阶段(Propose)
- 提议者(Proposer) 选出一个区块并广播。
- 可能情况:
- 若区块有效且按时收到,则进入 Prevote Block。
- 若区块无效或未及时收到,则进入 Prevote Nil。
- Prevote 阶段
- Prevote Block(若收到有效区块):
- 等待至少 2/3 的 Prevote 票数(Wait for prevotes from +2/3)。
- Prevote Nil(若未收到有效区块):
- 进入 Precommit Nil,即该轮未能达成共识。
- Prevote Block(若收到有效区块):
- Precommit 阶段
- Precommit Block(若 2/3 以上的节点 Prevote 了该区块):
- 进入等待 Precommit(Wait for precommits from +2/3)。
- Precommit Nil(若未达成 2/3 Prevote):
- 进入新的轮次(New Round),重新开始提议流程。
- Precommit Block(若 2/3 以上的节点 Prevote 了该区块):
- Commit 阶段
- 若 2/3 以上的节点 Precommit 了该区块:
- 区块最终被 提交(Commit),状态更新,进入新高度(New Height)。
- 否则,重新进入 New Round,重复上述流程。
- 若 2/3 以上的节点 Precommit 了该区块:
核心逻辑总结
- 三阶段投票机制(Prevote → Precommit → Commit)
- 需要 2/3 以上的投票支持 才能进入下一阶段。
- 若任何阶段未能达成 2/3 共识,则进入新一轮(New Round)。
- 区块有效性判断
- 若提议区块无效或未按时收到,节点会投 Prevote Nil,影响共识进展。
- 在 Prevote 或 Precommit 阶段,若未达到 2/3,进入新轮次。
- 最终性(Finality)
- 当 2/3 以上的节点 Precommit 了某个区块,则该区块最终会被 Commit,不会被回滚。
Hyperledger fabric 和 cometBFT 的本质差异
- Hyperledger Fabric 的 PBFT 有 pre-prepare 选择主节点的过程,但是 cometBFT 没有,这就很大程度上提高了算法的效率
Tendermint 相比经典 PBFT 的两个关键改进:一是轮流提议 ,出块权按质押权重轮换,省掉了昂贵的 view change 选主;二是锁定机制,节点一旦对某个区块投了 Precommit 就被"锁"在它上面,后续轮次不能随便改投别的区块,这保证了即使网络异步分区,也不会同时提交两个冲突区块。HotStuff 则进一步把通信复杂度从 O(n²) 降到 O(n),通过门限签名把一轮投票聚合成一个法定人数证书(QC),为更大规模的验证者集合铺路。
其他的 PBFT 变种算法(扩展)
- HotStuff BFT: libra 项目用户的
- Avalanche: 雪崩链自研 PBFT 算法
用一段 Python 模拟 PBFT 的三阶段投票,可以直观看到「为什么必须收到 2f+1 票」:
python
from collections import Counter
N, F = 7, 2 # N = 3f + 1,f = 2
QUORUM = 2 * F + 1 # 需要收集的票数 = 5
def pbft_round(primary: int, faulty: set[int], msg: str) -> bool:
replicas = list(range(N))
# 阶段一:pre-prepare,主节点广播提案
if primary in faulty:
print("主节点作恶/宕机,触发 view change")
return False
print(f"[pre-prepare] primary={primary} 广播提案: {msg}")
# 阶段二:prepare,副本节点校验后回复确认
prepares = [r for r in replicas if r not in faulty and r != primary]
print(f"[prepare] 收到确认票: {prepares}")
if len(prepares) + 1 < QUORUM: # +1 是主节点自己
print("prepare 未达 2f+1,进入新一轮")
return False
# 阶段三:commit,主节点广播 commit 并落块
commits = [r for r in replicas if r not in faulty]
print(f"[commit] 收到提交票: {commits}")
if len(commits) < QUORUM:
print("commit 未达 2f+1,进入新一轮")
return False
print(f"区块提交成功: {msg}")
return True
if __name__ == "__main__":
print("=== 正常情况 ===")
pbft_round(primary=0, faulty=set(), msg="block#100")
print("\n=== 2 个节点作恶 ===")
pbft_round(primary=0, faulty={3, 4}, msg="block#101")
把 faulty 集合扩大到 3 个节点(超过 f),你会看到 quorum 无法达成------这就是 N = 3f + 1 的边界。
三、P2P 协议
图解 P2P

点对点通信:节点与节点之间之间链接通信,没有通过任何的第三方服务进行连接,而是直接通信
P2P 通信协议详解P2P(Peer-to-Peer,对等网络)通信协议是一种去中心化的网络通信架构,允许网络中的节点(对等体)直接相互连接、交换数据和资源,而无需依赖中央服务器。这种协议相对于传统的客户端/服务器(C/S)模式,具有更高的可扩展性、容错性和资源利用效率。P2P 协议最早可追溯到 1969 年的 RFC1 文档,但真正流行于文件共享领域,如 BitTorrent 协议。
P2P 协议的基本原理
P2P 协议的核心思想是将网络中的每个节点视为平等的参与者(Peer),每个 Peer 既可以作为客户端请求资源,也可以作为服务器提供资源。这种设计避免了 C/S 模式中的单点故障和带宽瓶颈问题。
- 去中心化结构:在 C/S 模式下,所有数据从中央服务器分发,服务器负载高且易失效。P2P 则通过分布式方式,让节点间直接通信,资源(如文件)被分割成小块(Pieces),节点间交换这些块,最终组装完整数据。
- 资源共享机制:下载者同时也是上传者。参与节点越多,整体下载速度越快,因为资源分布在多个 Peer 上。
- NAT 穿越与打洞技术:由于大多数节点位于 NAT(Network Address Translation,网络地址转换)设备后,P2P 需要解决"穿透"问题。常见技术包括 STUN(Simple Traversal of UDP through NATs)、TURN(Traversal Using Relays around NAT)和 ICE(Interactive Connectivity Establishment)。这些协议帮助节点发现公网 IP 和端口,并在防火墙/NAT 上"打洞"建立直接连接。
- 例如,在两个 NAT 后的节点通信时,先通过公共服务器交换映射信息,然后尝试直接链接。
P2P 属于覆盖网络(Overlay Network)范畴,节点通过逻辑链接形成虚拟网络,底层通常基于 TCP/UDP 协议。
落到区块链上,P2P 承担两类流量:交易传播 和区块/状态同步。交易通常用 Gossip(流言)协议泛洪:节点收到新交易后随机转发给若干邻居,邻居再转发,几跳之内全网可见;区块传播则讲究"越快越好",因为慢一步就可能产生分叉。节点发现方面,比特币用硬编码种子节点 + DNS 种子 + 节点间地址交换,以太坊用基于 Kademlia 的 discv4/discv5 发现协议。把要点整理成表:
P2P 节点发现与消息传播要点
| 环节 | 关键技术 | 作用 | 区块链中的对应 |
|---|---|---|---|
| 节点发现 | Tracker / DHT / PEX | 找到可连接的 Peer | 种子节点、DNS 种子、discv5 |
| NAT 穿越 | STUN / TURN / ICE | 让内网节点建立直连 | 节点打洞、中继兜底 |
| 消息传播 | Gossip 泛洪 | 交易/区块快速扩散全网 | txpool 交易广播、新区块广播 |
| 数据校验 | 分片哈希校验 | 防止传输中被篡改 | 区块头哈希、Merkle 证明 |
| 拓扑组织 | 结构化 / 非结构化 | 平衡查找效率与鲁棒性 | Kademlia DHT、随机邻居图 |
提示:P2P 网络天然开放,任何人都能跑节点接入,所以要靠签名和哈希校验来防恶意数据,靠节点评分/封禁来对抗 Sybil 与垃圾消息。
Gossip 泛洪是区块链 P2P 最核心的消息传播方式,下面用几十行 Python 模拟一个简化版网络,观察一条交易几跳能覆盖全网:
python
import random
from collections import deque
class Node:
def __init__(self, nid: int, peers: list[int]):
self.nid = nid
self.peers = peers
self.seen: set[str] = set()
def build_network(size: int, degree: int = 4) -> dict[int, Node]:
nodes = {}
for i in range(size):
peers = random.sample([j for j in range(size) if j != i], degree)
nodes[i] = Node(i, peers)
return nodes
def gossip(nodes: dict[int, Node], origin: int, tx_id: str, fanout: int = 3):
"""从 origin 节点泛洪一条交易,返回每个节点首次收到消息的跳数。"""
hops = {origin: 0}
queue = deque([origin])
nodes[origin].seen.add(tx_id)
while queue:
cur = queue.popleft()
targets = random.sample(nodes[cur].peers, min(fanout, len(nodes[cur].peers)))
for nxt in targets:
if tx_id in nodes[nxt].seen:
continue
nodes[nxt].seen.add(tx_id)
hops[nxt] = hops[cur] + 1
queue.append(nxt)
return hops
if __name__ == "__main__":
random.seed(42)
net = build_network(size=200, degree=4)
result = gossip(net, origin=0, tx_id="tx-abc")
print(f"覆盖节点数: {len(result)}/200")
print(f"最大跳数: {max(result.values())}")
print(f"平均跳数: {sum(result.values()) / len(result):.2f}")
可以看到在随机图 + 小 fanout 的情况下,200 个节点通常 4~5 跳就能全覆盖,这就是 Gossip 高效又鲁棒的原因;代价是存在冗余消息,需要靠 seen 集合去重。
P2P 网络的组织结构
P2P 网络有多种拓扑结构根据应用场景选择:

这些结构确保节点高效定位和通信。
- P2P 协议的工作流程以 BitTorrent(经典 P2P 文件共享协议)为例,说明典型工作过程:
- 种子文件生成:文件被分成固定大小的分片(e.g., 2MB/片),生成 .torrent 文件,包含分片索引、哈希校验和 Tracker 服务器地址。
- 连接 Tracker:客户端从 Tracker 获取其他 Peer 的 IP/端口列表。
- Peer 发现与连接:使用 DHT 或 PEX(Peer Exchange)发现更多 Peer,建立 TCP/UDP 连接。
- 数据交换:节点间查询已下载分片,交换缺失部分。同时上传已下载内容。
- NAT 穿越:如果失败,使用 TURN 中继服务器转发数据。
- 完成与共享:下载完成后,节点继续作为 Seed(种子)上传,帮助他人。
其他协议如 Wi-Fi Direct(Wi-Fi P2P)则专注于设备间直接连接,无需路由器,支持数据传输。
P2P 协议的应用场景
P2P 广泛应用于多个领域:
- 文件共享:BitTorrent、eMule 等,高效分发大文件。
- 流媒体:P2P 直播/点播(如 PPLive),节点间共享视频流,降低服务器压力。
- 即时通信:Skype、QQ 使用 P2P 实现语音/视频通话,减少延迟。
- 区块链:比特币等使用 P2P 网络同步区块数据。
- 分布式计算:利用节点 CPU 进行科学计算(如 SETI@home)。
- 云存储:如 IPFS(InterPlanetary File System),分布式存储文件。
- 游戏平台:在线游戏支持 P2P 匹配和数据同步。
P2P 协议的优缺点
- 优点:
- 高效性与可扩展性:参与者越多,速度越快;无单点瓶颈。
- 鲁棒性:节点故障不影响整体网络。
- 隐私与安全性:减少中央服务器依赖,数据直接传输(但需加密)。
- 成本低:利用用户带宽,降低基础设施开销。
- 缺点:
- 安全风险:易受恶意节点攻击(如 Sybil 攻击),传播病毒。
- 网络质量依赖:带宽不均、节点 churn 导致不稳定。
- 监控难题:去中心化使监管困难。
- NAT 兼容性:需额外技术处理 Symmetric NAT 等复杂类型。
未来趋势与挑战
P2P 技术正向更安全的方向发展,如结合区块链增强信任。目前研究焦点包括节点延迟优化、Inter-Overlay 优化和 P2P 安全。
四、总结
- POW
- POS
- PBFT
- P2P
用一句话收尾:共识算法决定"账本以谁为准",P2P 决定"消息怎么传到大家手里",两者一个管决策、一个管通信,合起来才是一条能跑的链。选型时的经验法则是:公开无许可网络优先 PoW/PoS 这类抗女巫的机制,小规模许可网络可以用 PBFT/Tendermint 换取确定性终局和高吞吐。
本文是 Web3 基础知识系列的第 5 篇,
整套笔记从区块链的由来、密码学原理、组织结构、共识与公链实践逐讲展开。
五、参考资料 & 致谢
参考资料
- Bitcoin 白皮书 :Satoshi Nakamoto, Bitcoin: A Peer-to-Peer Electronic Cash System, 2008 --- PoW、最长链原则与概率终局的原始出处。
- Ethereum 官方文档 :https://ethereum.org/zh/developers/docs/consensus-mechanisms/pos/ --- PoS、验证者、checkpoint 与 finality 的权威说明。
- Ethereum Engine API 规范 :https://github.com/ethereum/execution-apis/tree/main/src/engine ---
engine_newPayload/engine_getPayload/engine_forkchoiceUpdated的接口定义。 - EIP-7251(Pectra 升级) :https://eips.ethereum.org/EIPS/eip-7251 --- 验证者最大有效余额从 32 ETH 提升到 2048 ETH 的依据。
- PBFT 原始论文 :Miguel Castro, Barbara Liskov, Practical Byzantine Fault Tolerance , OSDI 1999 --- 三阶段共识与
N = 3f + 1的推导。 - Tendermint / CometBFT 文档 :https://docs.cometbft.com/ --- Propose / Prevote / Precommit / Commit 状态机说明。
- HotStuff 论文 :HotStuff: BFT Consensus with Linearity and Responsiveness, PODC 2019 --- 线性通信复杂度 BFT 的代表工作。
- Hyperledger Fabric 文档 :https://hyperledger-fabric.readthedocs.io/ --- 0.6 版 PBFT 与 1.0 之后排序服务(Kafka/ZooKeeper、Raft)的演进。
- BitTorrent 协议规范 :https://www.bittorrent.org/beps/bep_0003.html --- 分片、Tracker、PEX 与 DHT 的经典实现。
- Kademlia 论文 :Petar Maymounkov, David Mazières, Kademlia: A Peer-to-Peer Information System Based on the XOR Metric, 2002 --- 以太坊 discv4/discv5 的理论基础。
- RFC 1 :https://www.rfc-editor.org/rfc/rfc1 --- P2P 思想最早可追溯的文档。
致谢
- 感谢 CSDN 平台提供的创作与发布环境,让这套 Web3 基础知识笔记得以系统整理成文。
- 感谢以太坊基金会、比特币核心开发者以及 CometBFT、Hyperledger 等开源社区,本文大量概念与图示均受益于其公开文档与源码。
- 感谢所有在评论区指出错漏、补充案例的读者,你们的反馈让文中关于 PoS 罚没、Engine API 调用顺序、PBFT 容错边界等细节得以不断修正。
- 本文部分示意图来自公开技术资料,仅用于学习交流,版权归原作者所有;如有不当引用,请联系删除。
说明:本文为个人学习笔记,观点与理解难免有偏差,欢迎在评论区交流指正。若需转载,请注明出处。