Cardano SL中的Ouroboros权益证明算法
发布于 3 个月前 作者 liuchengxu 184 次浏览 最后一次编辑是 3 个月前 来自 其他链技术

译者:许莉

原文地址:https://cardanodocs.com/introduction/

Ouroboros权益证明算法是协议中最重要的部分。它定义了节点对账本状态达到共识的方法。

Ouroboros是独特的,因为它是第一个基于权益证明的区块链协议,并被科学地证明是安全的。

为什么选择权益证明?

选择权益证明算法而不选择被比特币采用的工作量证明算法最重要的原因是对能量消耗的考虑。运行一个比特币协议是非常昂贵的。估计产生一个比特币交易消耗的电力大概是3.8个美国家庭一天消耗的电力。运行比特币协议所需的电力随着越来越多的旷工将资金投入到挖矿中逐渐增长,电脑(挖矿机器)需要算力解决的问题难度系数也会增加。这也是为什么研究者们努力的研究其他的方法来达到共识——例如使用所谓的拜占庭容错(BTF)共识算法和权益证明算法。

什么是权益证明?

在此章节中我们解释“证明”和“权益”是什么意思,然后把它们放到一起,解释“权益证明”是什么意思。

证明

“权益证明”中的“证明”是指对于区块中的交易是合法的有个证据。

权益

“权益”指的是“节点中的地址所持有的相对价值”。我们说“相对价值”其实就是“某个特定节点上的钱包所持有的所有价值除以系统中的总价值”。请阅读Cardano SL中的余额和权益来获取更多的信息。

权益证明

与其说旷工为了参与到权益证明环境中去运行该协议而投入大量金钱到挖矿机器上,还不如说领导者为区块链生产区块。任何人都可以成为领导者只要代币选择算法选中了他们所拥有的代币。我们说这个区块链是自我调节的,也就是区块链的维护是取决于网络参与者以及网络状态的。除了网络状态和网络参与者在线之外的任何其他问题对于权益证明而言都是无关的。

追随中本聪

让我们稍微详细的说明一下领导者是如何被选举出来的。最小的、原子价值被称之为"币(coin)"。在比特币中,原子价值被称之为"聪(Satoshi)",表达对比特币创造者中本聪的尊重。从根本上,我们可以说账本产生币分配。“追随中本聪”是一个算法,它可验证的挑选一个币,提供随机性。当你的币被选中,你就变成了一个领导者并且可以监听其他人宣布的交易,然后将这些交易组成一个块,用自己的私钥签名该块,最后将这个块发布到网络上。当然,你不用手动的去做这些事情——你的节点会帮你做所有的这些事情。

多方计算

具有随机性的"追随中本聪"算法的燃料问题就是另一个问题了。我们使用多方计算的方法产生真随机数:选择节点来提供所谓的“提交”,然后得到“揭示”,产生一个与网络参与者无关的随机数。

Cardano SL中的地址

为了发送和接收价值,几乎所有的加密货币都使用了地址。Cardano SL支持了3种地址类型:

  • 公钥地址
  • 脚本地址
  • 赎回地址

公钥地址在其他的加密货币中就像一个正常的地址一样。它是一个经过哈希的公钥。

脚本地址被用在一个所谓的P2SH交易中。它自主的运作,而且有点像银行里面的存款:你可以向它汇款,但是为了可以兑换这笔钱你必须要满足一些特定的条件,条件由与地址相关的脚本来决定。地址本身包含着序列化脚本的哈希值。

赎回地址是ADA赎回的一种特殊地址类型。

不仅如此,Cardano SL还支持Unknown的地址类型。这种类型可以允许我们在未来使用自定义的地址类型

地址看起来像什么?

地址是base58编码的字节串,例如:

Ae2tdPwUPEZKmwoy3AU3cXb5Chnasj6mvVNxV1H11997q3VW5ihbSfQwGpm

编码

base58就是比特币中使用的编码。它使用58个符号的字母表来编码数据,这也是它名字的由来。下面就是我们使用的字母表:

123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz

它跳过了非字母数字字符和在打印(0, O, I, l)时看起来模棱两可的字母;因此它适用于手动输入数据的人类用户,从一些可视化的源代码复制地址,并且允许通过双击来简单的拷贝和粘贴,不过双击通常会选择整个字符串。

公钥地址

就像在 Cardano SL的清算层中提到的那样,在用户界面你看到的钱包就是代表在这个特定的钱包中你拥有可以花费这笔钱的私钥。但是这样的花费是如何被网络验证的以及你如何接收到别人支付给你的钱?答案就是跟控制你钱包里面价值的的私钥一起会产生一个公钥,"公"是公共的意思,这个“公”的部分也就是指可以被任何人知道,因此叫做“公钥”。

一个公钥的地址包含了公钥的哈希值。

公钥在你创建一个交易或其他辅助用途的时候用来验证你的身份。

P2SH

P2SH的思想就是为花费金钱制定复杂的规则提供很大的灵活性。与发送一笔交易到公钥地址上相反,我们创建一个验证脚本,该脚本使用赎回脚本当参数。为了赎回里面的资金,我们传递一个赎回脚本给验证脚本,然后开始计算。如果计算结果为success,那么金钱就会被汇到指定的赎回者那里,否则的话什么都不会发生。

引用一下比特币 WiKi 里面的话:

使用 P2SH,你可以将比特币打给一个用多种不常见的方法保护着的地址,而不用知道该地址安全设置的任何详细信息。接收者可能需要多个人的签名来花费这些比特币,或者可能需要一个密码来花费这些比特币,也或者需要一个非常独特的要求才能花费这些比特币。

赎回地址

赎回地址就是P2PKH。这样的地址包含了赎回公钥的哈希值。并且这个钥匙是Ed25519公钥。

其他地址类型

在未来,我们可能会使用升级的系统来引入其他地址类型。请阅读 查看更多了解关于以无破坏性的方式的来扩展系统的相关信息。

地址结构

地址包含了3个部分:

  • 地址根
  • 地址属性
  • 地址类型

我们可以把地址想象成类似于JSON的结构,例如:

Address {
    addrRoot = AbstractHash e63175c654dfd93a9290342a067158dc0f57a1108ddbd8cace3839bd,
    addrAttributes = Attributes {
        data: AddrAttributes {
            aaPkDerivationPath = Nothing,
            aaStakeDistribution = BootstrapEraDistr
        } 
    },
    addrType = ATPubKey
}

addrRoot是由addrType、addrSpendingData、addrAttributes组成数组的BLAKE2b-224哈希值。

addrSpendingData是一个与地址绑定的特殊值,在花费该地址上的 coins 时必须要被揭露。例如,对于公钥来说,这个值就包含着公钥。这样的话,在不知道公钥的时候是不可能改变地址属性的,因为如果属性改变了,整个地址就变成无效的了。

addrAttributes包含了每个地址重要的属性:衍生的路径和权益的分配。

想要了解更多关于衍生路径请阅读Cardano SL的HD钱包。

想要了解更多关于权益分配请阅读Cardano SL中的交易。

addrType的值与上面提到的地址类型相对应。在上面的例子中它是一个公钥地址。

长度

地址的长度可能是不同的,地址长度与地址类型和附加数据相关。

例如,这个地址:

Ae2tdPwUPEZKmwoy3AU3cXb5Chnasj6mvVNxV1H11997q3VW5ihbSfQwGpm

和这个地址:

4swhHtxKapQbj3TZEipgtp7NQzcRWDYqCxXYoPQWjGyHmhxS1w1TjUEszCQT1sQucGwmPQMYdv1FYs3d51KgoubviPBf

都是公钥地址。

Cardano SL中的交易

概括

一个交易(tx)就是一组特殊的数据,代表着节点间价值转移的行为(从用户的角度来看就是钱包之间价值的转移)。因此,当用户 Alice 汇款给用户 Bob 时,新的交易就产生了。让我们称该交易为Tx1,Alice 钱包下的节点称为N1,Bob 钱包下的节点称为N2。

节点N1会执行下面的步骤:

  • 创建一个Tx1交易然后用自己的私钥给交易签名
  • 将该交易发送给所有的节点(也就是相邻节点)
  • 将该交易保存到本地的数据中

N1的每个相邻节点也会将Tx1发送给自己相邻的节点,以此类推。然后某个领导者会将该笔交易放入到账本中的某个区块里面。请注意,如果网络处理高负荷的状态,可能需要很长的时间才能让交易真正的加入到某个区块中。

设计

每个交易都包含了一系列的输入和一系列的输出。交易Tx0的输出可以被用来当做其他交易如Tx1交易的输入,以此类推:

        Tx0                           Tx1

±---------------------+ ±---------------------+ | | | | | Inputs Outputs | | Inputs Outputs | | ±-----+ ±------+ | | ±-----+ ±------+ | | | In0 | | Out0 + | | | In0 | | Out0 | | | ±-----+ ±------+ | | ±-----+ ±------+ | | | In1 | | Out1 | | | | In1 | | Out1 | | | ±-----+ ±------+ | | ±-----+ ±------+ | | | … | | … | | | | … | | … | | | ±-----+ ±------+ | | ±-----+ ±------+ | | | InN | | OutM | | | | InN | | OutM | | | ±-----+ ±------+ | | ±-----+ ±------+ | | | | | ±---------------------+ ±---------------------+

输入和输出携带着关于金钱走向的信息:输入告知金钱是从哪里来的,输出告知金钱往哪里去。请注意上面有N和M,是因为实际的情况输入和输出的个数可能并不相同。

每个输入包含:

  • 交易TxN的ID,TxN的输出就是该输入(每笔交易的输出就是另一笔交易的输入) 交易ID是一个交易BLAKE2b-256哈希值,大概就像这样: f9bcbe752aee4512457f1fd350200cf870906b7e6e836688c9a3779645c86c01.

  • 在 TxN的输出中使用的输出的索引

每个输出包含:

  • 节点N的地址,该节点就是我们想要发送价值给它的节点。一个地址就是节点N的公钥哈希值的BLAKE2b-224哈希值。大概像这样: 1fsAhhf4E1LQDB8agSds8teuD4E7U8JsRESngEX52kinBhi 请阅读Cardano SL中的地址来获取更多关于地址的信息。

  • 我们想要汇款的金额。是一个64位无符号的整形数字,最大值为45000000000000000。

例如:

Tx 891971a4cc31e32… Tx f9bcbe752aee4512… ------------------------+ ±---------------------------------------------+ \ | | | / Outputs | | Inputs Outputs |\ ±-----------------+ | | ±----------------+ ±-----------------+ | / | Out0 | | | | In0 | | Out0 | |\ | ±-------------+ | | | | ±------------+ | | ±-------------+ | | / | | Value | | | | | | Tx id | | | | Value | | |\ | | 100 ADA | | | | | | 891971a4c… | | | | 100 ADA | | | / | ±-------------±------>> ------>>±------------+ | | ±-------------±------>> \ | | Node address | | | | | | Out index | | | | Node address | | | / | | a00e4bb2… | | | | | | 0 | | | | 88ca7f79… | | |\ | ±-------------+ | | | | ±------------+ | | ±-------------+ | | / | … | | | | … | | … | |\ ±-----------------+ | | ±----------------+ ±-----------------+ | / | | |------------------------+ ±---------------------------------------------+

节点a00e4bb2…产生交易f9bcbe752aee4512…,这个交易告诉我们:

  • 我们想要从地址为a00e4bb2…的当前节点发送100 ADA到地址为88ca7f79…的节点

  • 这笔钱对应于上笔ID为 891971a4c…的交易的第0个输出

验证

就像上面提到的那样,一个交易的输出会变成另一个交易的输入。在这种情况下我们就把这种输出称为花费的交易输出。因此,交易891971a4cc31e32…的一个输出Out0是一个花费输出,因为它已经是交易f9bcbe752aee4512…的输入。

但是这种花费不会立刻发生。所以一个还不是其他交易输入的输出就被称为未花费的交易输出,为了防止双花 ,只有未花费的输出才能被用来当做其他交易的输入。

所以在网络中的每个节点不仅仅接收交易,还会验证它们。为了验证交易,每个节点都必须保持着对未花费输出的跟踪,这样就可以验证发布的交易中的输入是未花费的输出。所有未花费的输出叫做 UTXO。它也是一个叫做全球状态的特殊key-value数据库的一部分。

交易合法的证明

在Cardano SL中的每笔交易都有一个证明(也叫做见证)来表示这笔交易是合法的。即使输出是一个未花费的输出,我们也需要证明我们有权利来花费它。由于一个TxN交易可以有多个输入,那么它的见证就包含了TxN中所有输入的见证,如果所有的输入都是合法的,TxN就是合法的。如果某个交易不是合法的,那么网络就会拒绝这笔交易。

因为有两种可用的节点地址类型所以我们使用两个对应的见证版本:基于公钥的和基于脚本的。

例如,公钥PK与交易签名使用基于公钥的见证:合法的输入必须使用与PK相对应的私钥进行签名。所以就可以检查这个签名是被接收了还是被拒绝了。

见证被存储在区块链中,每个人都可以看见,也可以检查和独立的验证它们。但是经过一段时间之后,节点为了节省空间可能会删除老的证明。分开存储交易和证明的技术被称为隔离见证(你可能听到过它,最近在比特币中实现了)。在这种策略下,交易和证明被存储在区块两个分开的地方,而且可以独立的进行处理。

权益分配

权益分配是Cardano SL的另一个组成部分,虽然和代理者没有直接的关系, 但都可以通过它来获取相应的利润分红。

有些地址有多个拥有者,这也产生了一个权益计算的问题,因为每个追随中本聪算法的每个币对于每个股东的总权益而言只能计数一次。与余额(余额中币真正的数量)不同,权益赋予用户权利去控制不同的算法部分:成为领导者、进行投票更新系统、参加MPC/SSC。

权益分配是一个关联了每个地址的值。技术上说该值其实是地址属性的一部分,该值对应于下面三种情况下的某一种:

  • Bootstrap时代分配。这是一个特殊的值,它是Bootstrap时代里面的受托者,但是它在Bootstrap时代之后还可以使用。
  • 单个钥匙分配,这是指所有的权益会被分配给一个指定的股东。在这种分配情况下会包含股东的身份
  • 多个钥匙分配,这是指权益会被分配给多个股东(最少两个)。在这种分配情况下包含一对"股东们的身份 - 一个输出的部分"信息。交易的输出都有一个值,该值的一部分就是权益

领导者选举处理过程和富人计算两者都考虑到了权益分配。

这个特征可以以类似的方式用在委托中,但是有点区别:

  • 这里没有凭证:要撤销委托A必须要移动基金,提供不同的权益分配
  • A的部分权益可以通过分配来委托。相反的是,委托需要你同时委托全部地址的基金

Cardano SL中的权益委托

这篇文章是讲解权益委托过程的实现细节。

就像前面说的那样,被选举为领导者的股东为了产生新区块必须在线。不过,这样的情况可能没什么吸引力,因为大多数当选的股东都必须为了刷新随机数而参与币投掷协议(领导者选举过程的关键属性)。如果有很多当选的领导者,这会让股东和网络都有很大的压力,因为可能需要广播和存储大量的提交以及共享。

委托的特性允许被称为发行人I1…In的股东们将他们的“委员会参与”转移给某些代表团D1…Dm。这些代表团将会在币投掷协议中代表股东S1…Sn。这样的话真正参与到币投掷协议中节点数量就少很多,可以看看白皮书的第38页。

不仅如此,代表团不仅仅可以生产新区块或参与到MPC/SSC中,而且还可以在系统更新中进行投票。

策略

领导者可以将自己生产新区块的权利转移给代表团。为了转移这个权利,领导者使用一个代理委托的策略:领导者产生一个代理签名钥匙,或者说PSK,然后代表团会使用它签名信息来认证一个块。有两种类型的PSK:重量级和轻量级(看下文)。

具体来说,股东通过自己的公钥构建一个特殊的证书来指定代表团的身份。因此,稍后代表团可以在有效的信息空间内通过在自己的公钥下为这些信息提供的签名以及签署的证书给信息签名。

这是代理签名的格式。它包含了:

  • 代理私钥
  • 签名

代理私钥包含了:

  • omega 值
  • 发行人的公钥
  • 代表团的公钥
  • 代理证书

Omega(或者说ω)是一个特殊的值。在我们的实现中,它是一对时代的标识符。这些标识符定义了委托有效期:如果时代索引在这个范围内那么生产的区块就是有效的。

代理证书就是Omega和代表团公钥的签名。

重量级委托

重量级委托使用权益阈值T。意思是股东拥有的权益不少于T的时候才能参与重量级委托。这个阈值在配置文件中定义了。就像主网的这个阈值是总权益的0.03%。这个值可以通过系统更新来改变。

来自重量级委托的代理签名证书存储在区块链中。请注意发行者在每个时代只能发布一个证书。

请注意重量级委托有一个传递关系。所以,如果A委托给B,然后B又委托给了C,那么现在C代表的权益等于A + B,而不仅仅只是B。

到期

重量级委托证书如果在每个时代的开始不再传递阈值T那么它就会过期。这样做是为了预防委托池膨胀攻击:用户提交一个证书然后将自己所有的钱(高于阈值)都转到另一个账户,并且重复此操作。

轻量级委托

注意:当前轻量级委托功能是关闭的,在Shelley发布版本中会打开此功能,所以下面的信息可能是过期的。

与重量级委托相反,轻量级委托不要求代表团拥有T或更多的权益。所以轻量级委托可以用于任何的节点。但是轻量级委托的代理签名证书不存储在区块链中,所以轻量级委托证书必须要广播到代表团。

稍后轻量级PSK可以被指定发行者的公钥、签名和信息本身进行验证。

请注意“每个时代只有一个证书”的规则在轻量级委托中不采用。因为轻量级委托证书不存储在区块链的里面,所以有可能在每个时代签发很多轻量级证书也不会导致膨胀。

确认代理签名交付

代表团应该使用他拥有的代理签名钥匙使用PSK和代表团的钥匙制作一个PSK签名。如果签名是正确的,那么就是由代表团进行签名的(由PSK策略确保是这种结果)。

为什么有两个委托?

你可以将重量级委托和轻量级委托想象成强委托和弱委托。

重量级委托证书被存储在区块链中,所以被委托的权益可能会通过加入到委托权益中而参与MPC。所以有很多重量级委托的代表团可能会累计足够的权益去通过阈值的门槛。不仅如此,重量级委托可以参与Cardano SL更新的投票。

与此相反的是,轻量级委托的权益不会被计算到代表团的MPC相关的权益。所以轻量级委托只可以用来生产新区块。

撤销证书

撤销证书是一个特殊的证书,发行者创建一个撤销证书来撤回委托。重量级委托和轻量级委托都可以被撤回,不过撤回的方法不同。

作为发行者和委托是相同的标准PSK,撤销证书也是相同的。(换句话说,发行者委托给他自己)。

要撤销轻量级委托,发行者发送撤销证书给网络,要求撤销委托,但是不能强制撤销,因为轻量级的PSK不是区块链的一部分。所以,理论上轻量级委托是可以忽略撤销证书的,这样的话,它就一直保持着委托直到它的委托过期。但是这样的情况不会妨碍区块链。

重量级委托撤销的处理是另一种方式。因为来自重量级委托的代理签名证书是存储在区块链中的,撤销证书也会被提交到区块链中。这样的话节点会删除撤销证书签发之前的重量级委托证。不过有三个重要点:

  • 如果提交的重量级委托证书是在节点的内存池里面,而且撤销证书也被提交了,那么委托证书将会从内存池中被删除 显然,这种情况下委托证书将永远不会添加到区块链中

  • 如果一个用户提交重量级委托证书之后丢失了它的钱,他仍然可以撤销那个委托,即使那个时候他已经没有足够的钱了(也就是他拥有的钱少于上面提到的阈值T)

  • 尽管发行者在当前的时代只能发布一个证书,但是在同一个时代他可以撤销他的重量级委托。

网络拓扑

节点组

虽然Cardano SL被设计和实现为一个分布式的网络,但是为了DDoS的保护作用,额外的功能被添加到了Cardano SL实现和拓扑中。当前所有的节点被分为三组:

  • 核心组
  • 中继组
  • 边缘组

让我们分开讲解一下每组的节点。

核心节点

核心节点是最重要的。

就像这里描述的,Byron发布版本我们将会把权益高效地锁定在核心节点联盟上。只有很少的节点可以成为领导者,所以只有这些节点有能力在这个时期生产新区块。这是网络核心节点能够很好的运行和维护区块链的精髓所在。我们为核心节点还提供了另外的安全级别:我们将它们放在中继节点周边,所以核心节点与公有网络隔离开,并且只允许中继节点与核心节点进行通信。这就是我们减少核心节点被攻击的方法。

请注意核心节点永远不会创建货币交易(只有边缘节点可以创建,请看下文)。

中继节点

你可以将中继节点想象成核心节点和公有网络的代理。

因为中继节点不是隔离的,所以它们可以被攻击,但是它们原则上是无状态的并且没有权益,因此它们可以被移除,也可以增加数量。如果中继节点崩溃,会导致拒绝服务,但是核心节点(和区块链)的完整性不会受影响。

由于中继节点没有任何的权益,所以它们不能成为领导者。不仅如此,它们也不能创建货币交易。

中继节点是完全被最初股东联合委员会控制的。

边缘节点

边缘节点是简单的节点,每个人都可以在自己的电脑上运行边缘节点。只有这些节点可以创建货币交易。

由于边缘节点没有任何的权益,它们也与中继节点一样不能成为领导者。此外,边缘节点不能直接的与核心节点通信,只能与中继节点和其他边缘节点进行通信。

回到顶部