论文分享 | Themis: 在拜占庭共识中实现排序公平性

追踪目前在区块链共识方向上的研究问题,分享一篇发表于2023年CCS会议上的论文,它解决在支持拜占庭容错的区块链共识中交易的公平排序问题,利用延迟排序的思想提出了一个简洁实用的方案。

论文摘要

这篇论文提出了一个名为Themis的方案,引入对交易进行公平排序的概念,使得在执行拜占庭容错共识的许可区块链中,实现交易排序公平性这一比较强的要求。这一要求在于不仅让处于不同区块的交易,排序结果满足多数共识节点的偏好,而且还可以让同一区块内的交易,排序结果也与多数共识节点的偏好匹配。其中,排序偏好为该共识节点接收两个不同交易时的顺序。Themis方案可以用最小的开销集成到现有的共识协议中,并且通过实验表明系统在公平排序上具有很强的实用性。

1 背景介绍

在去中心化金融(Decentralized Finance,DeFi)应用中,攻击者通过操控交易排序以牺牲普通用户的利益为代价而获利。在现有的共识协议中,存在一个“leader”完全控制交易的包含和顺序,并将此作为提案执行共识。因此排序操控是存在的,尤其是区块链系统,没有严格限制交易应该如何排序。共识安全的两个关键特性,一致性和活跃性,都没有强制要求交易到达的顺序与其最终排序之间的关系。

排序公平性保证系统能够阻止攻击者操控交易的顺序,令最终在账本中出现的交易顺序能够反映交易抵达到网络中的顺序。Themis方案实现了与Aequitas方案同样强的公平属性,其排序公平性的概念也源自Aequitas论文中的形式化描述。此外,相关工作Pompe和Wendy的类似特性也用来与本论文所提方案进行比较。

Themis方案执行在一个部分同步网络下,包含 n n n 个节点且可容忍 f < n / 4 f < n/4 f<n/4 拜占庭敌手的共识组中,实现的公平排序属性即 batch-order-fairness ,形式化描述如下:

  • 定义( γ \gamma γ-batch-order-fairness):假设所有忠诚节点接收到了两笔交易 t x tx tx t x ′ tx' tx 。如果有 γ \gamma γ 比例的忠诚节点在交易 t x ′ tx' tx 之前接收到了交易 t x tx tx (其中 1 2 < γ ≤ 1 \frac{1}{2} < \gamma \leq 1 21<γ1 ),那么所有的忠诚节点应当在交易 t x ′ tx' tx 之前输出交易 t x tx tx

Themis方案可以在协议设计用最小的改动,从任意基于“leader”的共识协议中启动。首先,在构建区块之前,所有节点向当前的领导节点发送它们接收到的交易顺序信息;然后,指定一个算法让诚实的领导节点根据交易顺序信息构建公平的区块提案;最后,为所有节点提供一种方法来验证提案的公平性并输出最终排序。

论文用到了被称为延迟排序的技巧,领导节点发布的区块有部分交易是完全排序,其他的是部分排序。部分排序的交易由之后的忠诚领导提供排序信息,从而将这些交易的排序状态转变成完全排序。

2 问题来由

交易的公平排序问题来源于投票理论中的孔多塞悖论(Condorcet Paradox),一个抽象的解释是:即使参与投票的每一方在其本地的偏好是可传递的,也同样会出现非传递的全局偏好。维基百科(https://en.wikipedia.org/wiki/Condorcet_paradox)给出了一个经典的例子,假设有3个候选项A,B和C,3个节点对该候选集合的投票偏好恰好为[A,B,C],[B,C,A]和[C,A,B],列出投票偏好表如下。

投票人第一选择第二选择第三选择
节点1ABC
节点2BCA
节点3CAB

从任一节点视角看,候选项的排序是传递的,然而当采用多数节点原则合并全局结果时,候选项的全局排序变成了非传递的。如图1所示,全局偏好A排序在B之前,B排序在C之前,而C又排序在A之前,构成了孔多塞循环(Condorcet Cycle)。

图1 孔多塞循环示例

图1 孔多塞循环示例

本论文在排序公平性定义中的batch,即指打包一段时间内交易的区块。由于区块将交易分批打包,前一个区块中的任意交易在排序上优先于之后续区块中的所有交易,因此该孔多塞循环不必延申至无限长。重要的结果是,batch弱化了对公平性的定义,方案只需要关注并解决在同一个区块里产生孔多塞循环的交易。对孔多塞循环给出如下形式化定义:

  • 定义(Condorcet Cycle):称一个交易列表 [ t x 1 , . . . , t x l ] [tx_1,...,tx_l] [tx1,...,txl] 是长度为 l l l 的孔多塞循环需要满足:对于任意 i ∈ { 1 , . . . , l } i \in \{1,...,l\} i{1,...,l} ,其中 t x 1 = t x l + 1 tx_1 = tx_{l+1} tx1=txl+1 ,有至少 ( n − f ) ( 1 − γ ) + 1 (n-f)(1-\gamma)+1 (nf)(1γ)+1 个忠诚节点在交易 t x i tx_i txi 之前接收到交易 t x i + 1 tx_{i+1} txi+1

3 方案描述

Themis协议可以嵌入到任意基于领导的共识协议里,提供一种机制帮助节点检查区块提案的交易排序。为了构建这样的排序公平性,所有节点首先提交它们的本地排序偏好给领导节点,其本地排序依据节点接收交易的时间。协议引入了一种延迟排序的技巧,令忠诚节点分别执行 F a i r P r o p o s e \mathrm{FairPropose} FairPropose F a i r U p d a t e \mathrm{FairUpdate} FairUpdate 两个算法,前者用于构建包含了部分交易排序的区块提案,后者用于更新之前区块提案中未确定的交易排序。最后,通过执行 F a i r F i n a l i z e \mathrm{FairFinalize} FairFinalize 算法,节点可以在前两个算法构建的交易依赖图中提取出最终的公平排序结果。

3.1 符号定义

L \mathcal{L} L 是包含 n − f n-f nf 个节点的排序集合,用 t x ∈ k L tx \in_k \mathcal{L} txkL (对应的, t x ∉ k L tx \notin_k \mathcal{L} tx/kL)表示交易 t x tx tx 有至少(对应的,少于) k k k 个排序关系在集合 L \mathcal{L} L 中,用 t x ≺ ( L , k ) t x ′ tx \prec_{(\mathcal{L},k)} tx' tx(L,k)tx 表示至少有 k k k 个交易 t x tx tx 在交易 t x ′ tx' tx 之前的排序关系在集合 L \mathcal{L} L 中,用 W e i g h t L ( t x , t x ′ ) \mathrm{Weight}_\mathcal{L}(tx,tx') WeightL(tx,tx) 表示排序关系为 t x ≺ ( L , k ) t x ′ tx \prec_{(\mathcal{L},k)} tx' tx(L,k)tx 的最大数值 k k k

延迟排序的思路是将最终的全排序划分为多个轮,在后一轮出现的交易,其排序结果一定不在当前轮之前。基于节点的本地排序偏好,领导节点将交易分为三类: solidblankshaded ,用 non-blank 标记某个交易是 solidshaded

  1. solid 交易出现在大多数节点的本地排序偏好里,同时记录在当前的区块提案中,满足 t x ∈ n − 2 f L tx \in_{n-2f} \mathcal{L} txn2fL
  2. blank 交易出现较少节点的本地排序偏好里,并且被排除在当前的区块提案中,因此标记该交易为空白,自然该交易也不会出现在之前的区块,当条件满足 t x ∉ n ( 1 − γ ) + γ f + 1 L tx \notin_{n(1-\gamma)+\gamma f+1} \mathcal{L} tx/n(1γ)+γf+1L 时该情况发生。
  3. shaded 交易记录在当前的区块提案中,满足 t x ∈ n ( 1 − γ ) + γ f + 1 L tx \in_{n(1-\gamma)+\gamma f+1} \mathcal{L} txn(1γ)+γf+1L t x ∉ n − 2 f L tx \notin_{n-2f} \mathcal{L} tx/n2fL ,即根据现有的本地排序偏好数量还不足以给出排序结果,因此将其作为候选。

3.2 构建提案

首先,领导节点执行算法 F a i r P r o p o s e ( L ) \mathrm{FairPropose}(\mathcal{L}) FairPropose(L) 发起一个区块提案。


算法1 - F a i r P r o p o s e ( L ) \mathrm{FairPropose}(\mathcal{L}) FairPropose(L)

输入一个包含 n − f n-f nf 个本地排序偏好的集合 L \mathcal{L} L ,执行:

(1)构建依赖图

  • 创建一个空的图 G = ( V , E ) \mathcal{G}=(\mathcal{V},\mathcal{E}) G=(V,E)
  • 对于每个 non-blank 交易 t x tx tx ,添加一个点 t x tx tx 到集合 V \mathcal{V} V 中。
  • 对于每个交易对 t x , t x ′ ∈ V tx,tx' \in \mathcal{V} tx,txV ,令 k = W e i g h t L ( t x , t x ′ ) k=\mathrm{Weight}_\mathcal{L}(tx,tx') k=WeightL(tx,tx) k ′ = W e i g h t L ( t x ′ , t x ) k'=\mathrm{Weight}_\mathcal{L}(tx',tx) k=WeightL(tx,tx) 。如果 k ≥ n ( 1 − γ ) + γ f + 1 k \geq n(1-\gamma)+\gamma f+1 kn(1γ)+γf+1 k ≥ k ′ k \geq k' kk ,并且 ( t x ′ , t x ) ∉ E (tx',tx) \notin \mathcal{E} (tx,tx)/E ,那么添加一条边 ( t x , t x ′ ) (tx,tx') (tx,tx) 到集合 E \mathcal{E} E 中。
  • 计算出图 G \mathcal{G} G 的拓扑排序集合 S S S

(2)输出公平排序

  • 令交易 V V V 为拓扑排序集合 S S S 中最后一笔 solid 交易。
  • 移除在图 G \mathcal{G} G 中所有排序在交易 V V V 之后的在集合 S S S 中出现的交易。
  • 输出图 G \mathcal{G} G 。|

交易依赖图的构建如算法1所示,首先将每个 non-blank 交易加入到图中,若交易满足 t x ≺ ( L , t h r e s h ) t x ′ tx \prec_{(\mathcal{L},\mathit{thresh})} tx' tx(L,thresh)tx 则添加边 t x , t x ′ tx,tx' tx,tx到图中,其门限值 t h r e s h = n ( 1 − γ ) + γ f + 1 \mathit{thresh} = n(1-\gamma)+\gamma f+1 thresh=n(1γ)+γf+1 。令 k = W e i g h t L ( t x , t x ′ ) k=\mathrm{Weight}_\mathcal{L}(tx,tx') k=WeightL(tx,tx) k ′ = W e i g h t L ( t x ′ , t x ) k'=\mathrm{Weight}_\mathcal{L}(tx',tx) k=WeightL(tx,tx) ,如果 k , k ′ ≥ t h r e s h k,k' \geq \mathit{thresh} k,kthresh k > k ′ k>k' k>k 则添加边 ( t x , t x ′ ) (tx,tx') (tx,tx) k ′ > k k'>k k>k 则添加边 ( t x ′ , t x ) (tx',tx) (tx,tx) 。两种排序只有其一会被加入到图中,遇到 k = k ′ k=k' k=k 时,则通过确定性算法选择边。注意到,如果 k , k ′ < t h r e s h k,k' < \mathit{thresh} k,k<thresh ,则这两个交易的排序将在之后的区块提案中以边的形式补充到图中。

然后,领导节点从图中排除 shaded 交易,仅输出在当前区块提案中的 solid 交易作为已确定结果的交易排序。

3.3 排序更新

算法 F a i r U p d a t e ( L u p d a t e s ) \mathrm{FairUpdate}(\mathcal{L}_{updates}) FairUpdate(Lupdates) 允许后续领导节点添加缺失的边(其他节点的本地排序偏好)到之前领导节点构建的由区块提案输出的依赖图。


算法2 - F a i r U p d a t e ( L u p d a t e s ) \mathrm{FairUpdate}(\mathcal{L}_{updates}) FairUpdate(Lupdates)

一旦接收到包含了 n − f n-f nf 个节点对于之前 shaded 交易的本地排序偏好的集合 L u p d a t e s \mathcal{L}_{updates} Lupdates ,执行:

(1)输出依赖

  • E u p d a t e s ← ∅ \mathcal{E}_{updates} \leftarrow \emptyset Eupdates
  • 对于所有的由同一个领导节点发起的区块提案中,在原有依赖图中不存在边关系的两笔交易 t x tx tx t x ′ tx' tx ,令 k = W e i g h t L u p d a t e s ( t x , t x ′ ) k=\mathrm{Weight}_{\mathcal{L}_{updates}}(tx,tx') k=WeightLupdates(tx,tx) k ′ = W e i g h t L u p d a t e s ( t x ′ , t x ) k'=\mathrm{Weight}_{\mathcal{L}_{updates}}(tx',tx) k=WeightLupdates(tx,tx) 。如果 t x ∈ n − 2 f L u p d a t e s tx \in_{n-2f} \mathcal{L}_{updates} txn2fLupdates k ≥ k ′ k \geq k' kk , 并且 k ≥ n ( 1 − γ ) + γ f + 1 k \geq n(1-\gamma)+\gamma f+1 kn(1γ)+γf+1 ,那么添加一条边 ( t x , t x ′ ) (tx,tx') (tx,tx) 到集合 E u p d a t e s \mathcal{E}_{updates} Eupdates 中。
  • 输出集合 E u p d a t e s \mathcal{E}_{updates} Eupdates

每个节点 i i i 发送集合 U p d a t e i \mathrm{Update}_i Updatei ,该集合包含了节点 i i i 看到的出现在之前区块提案中的 shaded 交易的排序。算法2收集这些集合并更新排序结果,如果 t x ≺ ( L , n ( 1 − γ ) + γ f + 1 ) t x ′ tx \prec_{(\mathcal{L},n(1-\gamma)+ \gamma f+1)} tx' tx(L,n(1γ)+γf+1)tx ,那么在之前的依赖图中添加边 ( t x , t x ′ ) (tx,tx') (tx,tx) ,更新的边在集合 ( E ) u p d a t e s \mathcal(E)_{updates} (E)updates 中,将补充到之前的图中计算最终公平排序结果。

3.4 结果输出

现在,一个完整的由某个领导节点发起的提案区块可以被定义为 B = ( G , E u p d a t e s , π = ( L , L u p d a t e s ) ) B=(\mathcal{G},\mathcal{E}_{updates},\pi = (\mathcal{L},\mathcal{L}_{updates})) B=(G,Eupdates,π=(L,Lupdates)) ,节点将使用 π \pi π 来验证排序的公平性。


算法3 - F a i r F i n a l i z e ( ) \mathrm{FairFinalize}() FairFinalize()

给定一个提案区块序列 [ B 1 , B 2 , . . . , B 3 ] [B_1, B_2, ..., B_3] [B1,B2,...,B3] ,执行:

(1)更新图

  • 对于所有区块 B i B_i Bi 不存在边的交易对 t x , t x ′ tx,tx' tx,tx ,如果边 ( t x , t x ′ ) (tx,tx') (tx,tx) 出现在集合 B j . E u p d a t e s B_j.\mathcal{E}_{updates} Bj.Eupdates 中,那么添加该条边到图 B i . G B_i.\mathcal{G} Bi.G 中。
  • k k k 为完成了提案内交易排序的最后一个区块的序号,即图 B k . G B_k.\mathcal{G} Bk.G 不存在缺失的边。
  • 计算图 B 1 . G , . . . , B k . G B_1.\mathcal{G},...,B_k.\mathcal{G} B1.G,...,Bk.G 的拓扑排序 S 1 , . . . , S k S_1,...,S_k S1,...,Sk

(2)产生公平排序

  • 对于每个拓扑排序 S i = [ v i 1 , . . . , v i l i ] S_i= [v_{i1},...,v_{il_i}] Si=[vi1,...,vili] ,其中 i ∈ { 1 , . . . , k } i \in \{1,...,k\} i{1,...,k} ,令 H i j H_{ij} Hij 为排序 v i j v_{ij} vij 哈密顿环首,可通过移除最小 w e i g h t weight weight 的边来选取。
  • t x i l i tx_{il_i} txili 是排序 v i l i v_{il_i} vili 中的一个 solid 交易,并且令 H i l i ′ H'_{il_i} Hili 为哈密顿回路 H i l i H_{il_i} Hili 的反向旋转,因此最后一笔交易为 t x i l i tx_{il_i} txili
  • 对于区块 B i B_i Bi 的最终排序输出为 H i 1 , . . . , H i ( l i − 1 ) , H i l i ′ H_{i1},...,H_{i(l_i-1)},H'_{il_i} Hi1,...,Hi(li1),Hili 。|

如算法3所示,根据后续提案中更新的本地排序偏好 B j . E u p d a t e s B_j.\mathcal{E}_{updates} Bj.Eupdates ,向已经之前的提案添加交易依赖图中缺失的边 ( t x , t x ′ ) (tx,tx') (tx,tx) 。在这样的更新操作之后,能够确定最新的完成了图关系的区块编号 k k k ,并将此之前的区块中的交易进行公平排序。

首先从区块产生的各个拓扑排序中找出存在的哈密顿回路,即第2章提到的孔多塞循环。然后从哈密顿回路中找出 w e i g h t weight weight 值最小的边,将其方向进行反向旋转从而切断回路,产生最终的公平排序。

3.5 公平排序的流程

如图2所示,给定一个 n = 5 , f = 1 n=5,f=1 n=5,f=1 的配置,即系统包含5个节点并容忍1个拜占庭错误,为简化示例令排序公平性参数 γ = 1 \gamma=1 γ=1

  • 第1步, n − f n-f nf 个节点提交本地排序偏好 L 1 \mathcal{L}^1 L1 给领导节点;
  • 第2步,领导节点运行 F a i r P r o p o s e \mathrm{FairPropose} FairPropose 算法创建区块 B 1 B_1 B1 ,包含交易的依赖图 G 1 \mathcal{G}^1 G1 ,其中 a , d a,d a,dsolid 交易, b , c b,c b,cshaded 交易;
  • 第3步,节点运行 F a i r F i n a l i z e \mathrm{FairFinalize} FairFinalize 算法输出交易列表 [ a ] [a] [a] 为当前的最终排序;
  • 第4步,节点提交 L 2 \mathcal{L}^2 L2 L u p d a t e s 2 \mathcal{L}^2_{updates} Lupdates2 给新的领导节点;
  • 第5步,新领导节点运行 F a i r P r o p o s e \mathrm{FairPropose} FairPropose F a i r U p d a t e \mathrm{FairUpdate} FairUpdate 算法创建区块 B 2 B_2 B2 ,其中包含了更新的边集合 E u p d a t e s 2 \mathcal{E}^2_{updates} Eupdates2
  • 第6步,节点运行 F a i r F i n a l i z e \mathrm{FairFinalize} FairFinalize 算法将边 ( b , c ) (b,c) (b,c) 加入到之前提案构建的依赖图 G 1 \mathcal{G}^1 G1 中,产生交易列表 [ b , c , d , e ] [b,c,d,e] [b,c,d,e] 追加到之前的最终排序之后。

图2 (\gamma=1)-Themis方案流程示例

图2 (\gamma=1)-Themis方案流程示例

4 性能对比

Themis方案基于Hotstuff共识协议,采用libhotsuff开源代码(https://github.com/hot-stuff/libhotstuff)进行程序实现,其源码同样公开在github仓库(https://github.com/dailinsubjam/Themis-code),主要的代码改动是在领导节点生成公平交易序列以及其他节点验证该序列的逻辑。

实验选取了两种配置,一个是所有节点都处于同一个区域,另一个是节点分散在不同的地域。同时,实验还选取了两种不同的区块大小参数,即一个区块包含的交易数量,分别为 β = 50 \beta=50 β=50 β = 400 \beta=400 β=400 。从实验结果可以看出,当节点分散在不同地域时,网络延迟大,Themis方案的嵌入对原有共识协议的性能影响较小。另外,当区块大小参数较小时,构建图的计算复杂度小,因而Themis方案的嵌入对原有共识协议的性能影响也比较小。实验的具体细节请阅读原始论文,本分享不做过多赘述。

学习笔记

这篇论文在原有的共识协议的基本属性中,合理地找出了一个新的问题,即对交易的排序公平性。该问题有孔多塞悖论这样的叙述做支撑,提出的方案简洁有效,且可直接嵌入到现有的基于领导提案的共识协议。从技术创新的角度来看,其对问题的把握发现要多余方案的整体设计。最后,附上文献引用和DOI链接:

Kelkar M, Deb S, Long S, et al. Themis: Fast, strong order-fairness in byzantine consensus[C]//Proceedings of the 2023 ACM SIGSAC Conference on Computer and Communications Security. 2023: 475-489.

https://doi.org/10.1145/3576915.3616658

以下是一个简单的 Java 代码示例,用于判断是否存在孔多塞悖论,并根据需要进行群体排序: ```java import java.util.*; public class VotingSystem { private int[][] preferences; // 二维数组,存储每个选民的排名列表 private int[] votes; // 存储每个候选人的得票数 private List<Integer> winners; // 存储获胜者的列表 /* 构造函数,初始化各个变量 */ public VotingSystem(int[][] preferences) { this.preferences = preferences; this.votes = new int[preferences[0].length]; this.winners = new ArrayList<>(); } /* 判断是否存在孔多塞悖论 */ public boolean hasCondorcetParadox() { int n = preferences[0].length; // 候选人数 for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { int count1 = 0, count2 = 0; for (int[] pref : preferences) { if (pref[i] < pref[j]) { count1++; } else if (pref[j] < pref[i]) { count2++; } } if (count1 > count2 && votes[i] < count1) { votes[i] = count1; } else if (count2 > count1 && votes[j] < count2) { votes[j] = count2; } } } int maxVotes = Arrays.stream(votes).max().getAsInt(); for (int i = 0; i < n; i++) { if (votes[i] == maxVotes) { winners.add(i); } } return winners.size() > 1; } /* 给出群体序 */ public List<Integer> getRanking() { if (hasCondorcetParadox()) { // 存在孔多塞悖论,需要按照特定属性序列来判断废票并剔除 // 这里假设废票为得分最低的一票 int minScore = preferences.length + 1; int loser = -1; for (int i = 0; i < winners.size(); i++) { int candidate = winners.get(i); int score = 0; for (int[] pref : preferences) { if (pref[candidate] == i + 1) { score++; } } if (score < minScore) { minScore = score; loser = candidate; } } for (int i = 0; i < preferences.length; i++) { if (preferences[i][loser] == winners.size() + 1) { // 该选民的废票 preferences[i][loser] = -1; } } } // 按照中位项定理给出群体排序 Map<Integer, Integer> scores = new HashMap<>(); for (int i = 0; i < preferences.length; i++) { for (int j = 0; j < preferences[i].length; j++) { if (preferences[i][j] > 0) { scores.put(j, scores.getOrDefault(j, 0) + preferences.length - preferences[i][j]); } } } List<Integer> ranking = new ArrayList<>(scores.keySet()); ranking.sort((a, b) -> scores.get(b) - scores.get(a)); return ranking; } } ``` 使用示例: ```java public class Main { public static void main(String[] args) { int[][] preferences = {{1, 2, 3}, {3, 1, 2}, {2, 3, 1}}; VotingSystem vs = new VotingSystem(preferences); if (vs.hasCondorcetParadox()) { System.out.println("存在孔多塞悖论,需要剔除废票"); } else { System.out.println("不存在孔多塞悖论,直接给出群体序"); } List<Integer> ranking = vs.getRanking(); System.out.println("群体序为:" + ranking); } } ``` 该示例中,我们使用一个简单的三选一投票的例子来测试代码。您可以根据实际情况进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值