作者:Bob McElrath

来源:https://btctranscripts.com/tabconf/2022/2022-10-15-braidpool/

本文为作者在 TABConf 2022 上的演讲的记录稿。记录者为 Bryan Bishop。

引言

今天我准备讲讲 Braidpool,这是一种去中心化的矿池协议。希望在座有人参加了今天早些时候的矿业圆桌,尤其是关于 p2pool 的。Braidpool 是 p2pool 的后继者。很久以前我做过一次关于有向无环图(DAG)区块链的演讲。

Braidpool

Braidpool 是一个去中心化的矿池提议,它使用了一个合并挖矿的 DAG 以及类中本聪的共识协议来跟踪矿工的贡献(shares)。这是我能够想象的最直接的在 DAG 上应用中本聪共识的想法。它保证了所有的矿工都会通过这个合并挖矿的另类区块链得到支付。它使用一套矿工的参与机制和一个很大的多签名机制(使用 FROST、ROAST 或者 MuSig2)来签名 coinbase 支付(或者说结算交易)。我们使用大规模多签名的能力,让这一切成为了可能。它会通过一个 “UTXO 集” 来跟踪矿池对矿工的欠款,这个 UTXO 实际上是一组交易(未花费的哈希化支付输出,Unspent Hasher Payment Output)。它瞄准的是参与者之间的恒定方差。每个矿工都有不同的挖矿难度,但我们希望为所有的矿工实现相同的出块率。它还允许发送矿工的贡献额,因此可以产生哈希率的期货和期权。可以是一个表示兆哈希(terahash)的币,你可以把它发送给别人,然后立即根据你提供的挖矿份额得到支付,或者基于此推出期货和期权。

大纲

有四个大类需要讨论。很久以前我曾经在推特上发表过我对这些分类的 “一般考量”。你必须定义什么是 shares(或者说 “准区块(weak blocks)”),然后你需要一种共识算法,我选择 Braid 是因为它的精神跟比特币最接近。然后你需要一种办法,将 coinbase (挖矿收益)合计到一笔滚动更新的交易中,表示(对矿工的)支付额的更新;最后,你需要签名,将收益支付给所有矿工。

Shares

在一个去中心化的矿池中,一个 “share” 就是一个准区块:一个完整的比特币区块,但不必然能满足比特币网络的出块难度。你从一个比特币区块开始,但这个区块并不必然能满足比特币网络的出块难度。这就是我要跟矿池中的其他所有人说明的事:我正在挖掘这个区块,要是我挖出了一个满足难度要求的区块,你们就会得到支付;我在遵守规则,要是我出了一个区块,你们会得到收益,反过来也如此,因为我们同在一个矿池中。支付交易按过往应该支付的数额滚动累加而成。还有一些元数据和没有承诺的元数据。

Share 承诺

你要承诺好多东西。Coinbase 交易里面有一个 OP_RETURN 输出,可以承诺一些元数据。它描述了谁挖出了这个区块,这个矿工的收款地址,以及跟这个矿工联系所需的其它元数据。比如说还需要这个矿工的 IP 地址。一旦你挖出一个区块,你就成了 FROST 协议的一个参与者,这是用来签名支付的,所以你要跟其他矿工沟通。

Share 元数据

区块的元数据哈希后放到 coinbase 元数据中。Coinbase 交易会承诺在区块头中,同时 coinbase 交易有两个输出,一个是 OP_RETURN 输出,表示 braidpool 和这个承诺,另一个则是一个地址。这个地址是一个使用 FROST 和 Schnorr 签名的非常大的多签名地址。

最后,还有一些不带承诺的元数据。使用一个 DAG 的原因在于,我们希望让出块率尽可能高、出块尽可能快。而问题在于时延。我们使用 DAG,这样就能在同一时间有多个区块制造者。我们需要一个易于辨析的时间戳。比特币的时间戳字段很小,有时候矿工会用完。如果我们希望构造对图谱的度量,我们就需要毫秒级的精度。当你把一个区块头交给一个矿工之后,TA 通常会拿回去计算几秒钟甚至几分钟。等这个矿工拿着 Share 回来时,时间戳已经超时 10 秒钟了。我希望使用 DAG 来度量网络的时延。在比特币网络中,孤儿块(oprhans)率用来衡量网络的时延。

孤儿率自身以及 DAG 中的高阶结构,可以度量时延。但是,要做到这一点,我们需要更好的时间戳。我加入了不带承诺的区块元数据,来包含该区块被广播的时间的时间戳。这也是证人时间戳:当我挖掘一个区块的时候,我也会提到我收到父区块的时间。这使我们可以度量网络的时延。

Share 价值

每个 Share 都有一个价值。许多对 share 的支付系统都是通过像 PPS(pay-per-share)这样的矿池来实现的。换句话说,矿池给出一个固定的价格,你依据自己提供的 share 数量,从一个综合基金中得到固定的数额。但是,去中心化的矿池没有额外的资金来源,只有来自 coinbase 的资金。所以,我们需要收集所有的手续费、所有的 coinbase 奖励,然后基于每人做了多少工作,按比例分发。

那么,人们到底做了多少工作呢?在同一个难度调整周期内,每个区块都有特定的工作量。在一个 DAG 中,这就变得更加模糊。如果我得到了一个菱形的图结构,这意味着什么呢?其中的工作量跟我把它们串联起来是一样的吗?可以直接加总吗?答案是可以,只要没有孤儿块就可以。

在一个这样的菱形结构里面,我们必须追问,出现孤儿块的概率有多大?我的幻灯片中的等式,使用在多于一个块的图谱(就像现在这种情形)中出现孤儿块的概率,为它们的工作量加权。

只要你的区块是连续的,你就可以加总工作量。但如果你的图是菱形的,那如何计算工作量呢?这不是一个简单的问题。区块出现是泊松分布,这就是在这些区块出现的同一时间窗口内出现两个乃至更多区块的概率。这既是 DAG 区块,也可以是比特币区块。

Share 得分

Shares 是对工作量的度量。它们是对 SHA256D 计算次数的静态度量。这有多大的价值?我们要到一个难度调整周期结束的时候才知道;一个难度调整周期长 2016 个区块。到那时候你就知道这个矿池挖出了多少区块,难度是多少。Share 的价格也因此设定。在那之前我们实际上并不知道。因此,我们每两周才能支付一次,而不是每个块都支付。所以,池子也要一直维持,直到知晓价格。一定的价格对应的 Share 数量会不断变化,因应难度的调整。这让我们可以制作出哈希率的期货和期权,以及其它基于算力的衍生品。

我们也因此可以把 Shares 发送到新的地址。

共识机制(Braid)

我们需要一种共识机制。这是一种记账系统,我们需要统计每个矿工贡献了多少 Shares 并加总它们。迁移到 DAG 意味着我们可以得到更快的出块速度。DAG 意味着区块可以有多个父母块。一个区块可以指向多个父块。“无环” 意味着在密码学上无法造成循环(除非能打破哈希函数)。它不是线性的,意味着区块没有高度。事实证明,DAG 可以在线性时间内排序。也有可能只是部分有序。

我们必须对广义的 DAG 作一些小小的限制。限制就是我不能把其他祖先块标记为父块。我把这称为 “辫子(braid)”。

Cohort

我有另一个关于 cohort 的演讲。一个 “cohort” 就是一个图的快照,是这个 DAG 里面可以被完全排序的区块的分组。在这里,以同一种颜色标注的区块中,图结构不能告诉我们它们出现的顺序。因此,在同一个颜色的区块中,任意一个都有可能在其它区块之前或者之后出现。但当你看到颜色变换的时候,这意味着右边的区块是左边的区块的子块。这就是每个人都同意的完整共识;在两次颜色变换中间,有些人还没收到某些消息,我们还不能获得完全的共识。

Cohert vs. 难度

因此我们可以做一些有趣的事情。我们可以定义一种难度调整算法。看看纵轴上的 cohort 时间,对比目标难度。如你所见,如果我们允许同一时间出现太多区块,那么 cohort 时间会变长,形成全局共识的时间会增加,因为网络中必须有静止的时期 —— 不产生区块,每个人都能收到所有信息的时期 —— 才能形成共识。根据泊松分布,如果区块率提升,那么出现静止时期的概率会下降。

难度调整

有一种让我们最容易达成共识的折中办法。这是一个公式,它让我们可以定义难度调整算法(retargeting algorithm)的零参数。对任意一段时间,我都可以度量 cohort 的数量、一个 cohort 中区块的数量、形成这个 cohort 的时长,然后我就可以分辨出为了实现最频繁达成共识,出块率应该设成多少才对。

矿工自选的难度

现在,我已经知道我想看到多少区块以及出块率了,现在,我希望矿工选出自己的难度。原理上,一个矿池的目的是降低(获得收入)方差。如果每个人都有相同的方差那就好办了,但更大的矿工有更低的方差。这个项目的目标是降低所有人的方差。如果我们允许矿工自选方差,在一个难度调整窗口期内他们可能会创建出更多或更少的区块。软件会选出一个难度,让所有的矿工拥有相同的方差。这不是由共识来执行的,你可以改变它,但一般来说没什么必要。

给定 10 分钟的比特币出块时间,只要每个人都在 braidpool 中挖矿,你会得到可能达成的最低方差。

嵌套式 braidpool

矿工甚至可以比进入一个次级矿池的门槛还要小。不用让矿池来管理 coinbase,我们可以复制关于 braidpool 的一切,然后启动一个新的,但这一次,你不是管理 coinbase,而是管理一个父矿池的输出。通过设置两个这样的 braidpool,更少的矿工也可以运行在另一个 braidpool 中,所以任意小的矿工都可以用最小的方差来挖矿。

冲突解决

Braidpool 将拥有一个交易系统,这意味着它也有双重花费问题。如果你有两笔相互冲突的交易,应该选择哪一笔呢?我们会保存所有的交易和所有的区块。比特币会放弃孤儿块。正是因为孤儿块和主链块的收益不对称,导致了 “自私挖矿” 问题。所以,在 braidpool 中我们保存所有的区块和交易,以解决自私挖矿问题。但如果有冲突交易,应该怎么办呢?

我把它称为 “后代工作量的简单加总法”。我尝试了许多算法,但这个似乎可以工作:不论图的结构如何,加总所有后代的工作量。图结构的问题在于它是可以被操控的,而且不需要花费多大的代价就能操控它。我想知道的只是特定的一笔交易之上有多少工作量累加了进去,然后选出最多的一条,这就是中本聪共识。相对于图结构,加总所有后代的工作量,用到了跟 share 的价值相同的数据。

这只在一个 cohort 内有意义。我不需要知道整条链,我只要看一个 cohort 内的各个区块的工作量即可。往下延伸得到的结论也适用于所有的祖先区块。

在平局的情形中,使用更小的哈希值来决定挖哪一条链。加入一个交易系统是 braidpool v2 要做的事。我希望让 braidpool 先运行起来、能够分发资金,然后再加入复杂的特性。

账款更新

怎样给每个人支付?每一个区块都产生了一个 coinbase。我们会滚动加总这些 coinbase。每个区块除了一笔 coinbase 交易,还有一笔交易会花费来自上一个区块的 coinbase 并键入到一个滚动的总和中,不断滚动下去。这就像很久以前公开的 eltoo 协议。

每一笔交易都有一个 “更新” 阶段和一个 “结算” 阶段。当我们把一笔 coinbase 放到一个区块中,这时候这笔交易就处于 “更新” 阶段。除了这个 coinbase 交易,还有这个 “账款更新” 交易 —— 这是一个输出,拥有来自这个矿池的所有输出。这个输出有 taproot 花费路径,可以产生结算交易,这就是我们保证每个人都得到支付的方法。

我把这种 taproot 支付称为 UHPO,是对 UTXO 集的类比。

结算交易:未花费的哈希化支付输出(UHPO)

如果这笔交易变得太大,可以分割成多笔交易。Braidpool 的目标就是管理这一笔大交易,这是所有人共享的账户。在 braidpool 关闭的时候,我们必须签名和广播这笔交易。但实际上这是一种乐观的协议,我们不会想主动发送这笔交易,但要是什么东西出错了,我们可以这样做,然后每个人都可以得到支付。还有其它办法从矿池中取走属于自己的钱。

支付的签名

然后,我们需要签名账款 —— 既包括滚动更新,也包括 UHOP 交易,这样它才能在必要的时候广播出去。在这个输出中,你需要两个公钥:一个更新公钥和一个结算公钥。这些公钥使用 FROST 或者 ROAST 的分布式密钥生成方法来生成。ROAST 基本上就是并行化的 FROST。在这些协议中,我们需要 DKG(分布式密钥生成),然后每个人都拿着私钥的一份碎片,一起拥有一个公钥。这个公钥会进入 coinbase 的 输出。需要做两次,一次生成更新公钥,一次生成结算公钥。

都是拜 FROST 和 ROAST 所赐我们才能做到这一点。在一个两周的窗口中,可能会有许多矿工加入、生产区块。所以我们可能需要做一个非常大的多签名设置,因为窗口很大。 FROST(?)可以允许高达 50 个签名人;我们可能需要用某种聪明的办法来结合 MuSig 和 FROST。

在发现一个比特币区块之后,就会触发一个签名仪式。我们不会提前签名。我们会延后签名。这个签名仪式可以在协议外(链下)发生。

衍生品与即时付账

Braidpool 的目标之一是支持 shares 的即时付账。假设你加入了一个矿池,这个矿池扣着你的资金,某一天你想取回自己的钱。其中一个人们一直在开发的方案是使用闪电网络来实现即时付账。我们这里也可以这样做,而它工作的原理是你找到一个对手方,把 shares 发送给他们,然后他们给你支付比特币。这可以用原子化互换或者闪电网络来完成。

在当今的去中心化矿池中,有一些实体会购买 shares。他们也承担着风险管理的角色。在大宗商品市场中,Citadel 会分析期货和期权的价格应该为何,然后在市场中做市。现在的矿池在一定意义上也是在做这样的事。我的目标是矿池可以实际上利用这种工具,因为这给了他们新的风险管理工具,他们可以做衍生品,然后将方差降低到使用原生比特币协议无法企及的水平。

这些哈希率衍生品工具将进入中心化的市场或者私人合约。我无意开发去中心化的交易所。但让 Shares 变成一种可转移的金融产品,就足以让中心化的交易所建立这些产品的市场。

时间线

我跟 Kulpreet Singh 一起开发,我也邀请各位加入我们。我正在使用 Jesse Posner 的 FROST 代码(来自 libsecp256k1-zpk)。我们希望尽快达成的目标之一是时延的优化。我们需要能够尽可能快地发送区块。BlueMatt 讲了一些关于中继网络的事情,比如使用 fountain 代码非常快地向周围发送区块,这是优化 braidpool 所需的,让在 DAG 上产生区块的速度变得非常快。

结论

现在我们已经有了 FROSTROAST,我之前的 DAG 技术也能工作,我们可以将这些东西结合起来,获得更好的去中心化矿池协议。这可以说是 p2pool 的一种直接的演化;p2pool 将每个人的账款直接放进 coinbase 交易,而在 braidpool 中,我们还是把它们放在外面。还有一个来自 Chrid Belcher 的提案,使用准-可信的闪电网络中心来给每个人支付。我的目标是让现有的矿池能运行在 braidpool 上,以及让他们使用 Stratum v2 协议。