作者:Nico Preti
来源:https://btctranscripts.com/bitcoinplusplus/layer-2/exploring-p2p-hashrate-markets-v2
原文为作者在 Bitcoin++ 的 Layer2 专题大会上的演讲的转录稿,由 sahil-tgs 通过 review.btctranscripts.com 转录。
引言
各位好,我叫 Nico,是 Rigly 的联合创始人,我们是一家点对点的哈希率市场。这场演讲的结构是这样的:首先,我们先聊聊什么是 “哈希率”、协调挖矿任务在网络中分发的协议;然后,稍微介绍一下哈希率市场的发展历程;最后,我们如何可以利用 Layer 2 来打造哈希率市场,这也是我们出现在这场会议上的理由。
哈希函数和哈希率
那么,什么是 “哈希率” 呢?
你看,这是一个哈希函数的输出。哈希函数就是,你把一个 “原像(preimage)” 投进去,它会输出一个映像(哈希值)。
在比特币的区块浏览器查看区块的时候,你会看到顶部有一个哈希值,它的十六进制形式以一连串的 0 开头。这个设计源自 Adam Back 的 “Hashcash” 项目。比特币的哈希率也都基于这种 hashcash 算法。
关于它是怎么工作的,你可以诉诸一种简单的数学:我们有 0 的 k 次幂(0^k)。屏幕上右边的这个输出(或者说映像),我们希望它以一定数量的 0 开头。因此,0^k 基本上就是难度,以开头要有多少个 0 为度量单位。
如果用代数来表示,那么我们可以写成一个函数,表示 X 的哈希值(H(x));以 x 为输入,希望输出的开头是一串 0 。这个函数的更好的表示方法是,你有一种哈希函数(H(s, c) ),它的 “服务字符串” 是 s,而 c 是一个计数器。这个计数器会递增。服务字符串是给这个哈希函数赋予实际意义的东西;不然的话你就只是在哈希一堆乱七八糟的东西,你的确可以证明,这个数字进入这个哈希函数之后就会得到这个输出,但这没有任何实际意义。所以服务字符串就是效用,在我们这里就是比特币区块。这个服务字符串是我们准备在整个网络中确认的交易所汇集而成的一个区块头。
Hashcash 项目使用 SHA-1,输出是 160 比特,我记得曾经将 k 设为 20,也就是你要尝试 100 万次才能找出一个正确的原像。比特币使用 256 比特,输出大得多,你要尝试的次数也多得多。Hashcash 与比特币的一个重大区别在于,Hashcash 在难度中使用 2 的 k 次幂(2^k),意味着在一个难度周期中,难度要么倍增、要么减半;而在比特币中,我们需要更加精准地调控每一个周期(2016 个区块)的难度。所以,我们将 k 变成一个浮点数,这样在调整难度时可以更加精确。每隔 2016 个区块,我们就要调整接下来一个周期的难度,最终变化的是这个浮点数。
最终我们要干什么呢?完整的数学表达是这样的,首先,你拿 s 作为服务字符串、x 作为你的随机起点(对于绝大部分矿工来说,这实际上会变成你可以影响默克尔根的 coinbase 交易,这个我们后面再说,但那也可以当成一种随机起点,因为每个矿工都在不停改变 coinbase 交易)。然后,不是让哈希值等于 0,而是小于某个难度目标(H(s,x,c) < 2^(n-k))。目标等于 2^(n-k) …… 这就是它的工作原理背后的一些数学描述。
挖矿过程概述
在比特币中,我们将区块头作为我们要哈希的东西(服务字符串)。作为一个矿工,你只需要给我一个区块头,然后我就能开始挖矿。那么区块头里有什么呢?这问题其实非常重要。
通常来说,人们在刚接触比特币的时候会了解到,但随后就会逐渐忘却。它会埋到你的脑海深处,你甚至不会记得区块里有什么。但它很重要:
首先,我们有
Version,就是你在运行的软件的版本号;然后是上一个区块的哈希值(
hashPrevBlock),正是因为留存了这个东西,区块才前后相接、形成了一条区块链;再然后是
hashMerkleRoot,就是我刚刚说过的,区块内的所有交易以一棵树的形式哈希成一个默克尔根;还有当前区块的时间戳(
Time),它每隔几秒就会改变一次;所以这里也有几个比特的随机性空间;还有
Bits,它是用十六进制来表示的难度;最后,是
Nonce,就是那个计数器。这个 nonce 字段实际上是非常非常小的,只有 32 比特,你使用现在的矿机,很快就能遍历这个空间。所以,为了成功挖出区块,我们不得不诉诸所谓的extranonce字段,它就放在coinbase 交易里面;改变了 coinbase 交易你就会影响默克尔根。
各位可能有所不知,今天,我们用来衡量矿机性能的指标,是 “TH(terahashes)”,是 10 的 12 次方(次哈希运算)。如果谈论的是一群矿机,比如说一个矿场,那就用 “PH(petahashes)”(10 的 15 次方)。最后,如果讨论的是整个网络的哈希率总和,我们通常用 “EH(exahashes)”(10 的 18 次方)为单位。目前,我认为整个网络的哈希率达到了 350 EH 。现在,标准的矿机每秒运行 100 TH,而中等规模的矿场每秒运行 10 PH 。
(译者注:作者在这里才算真正谈到衡量哈希率(哈希速度)的指标,比如普通的矿机是 100 TH/s ,每秒运行 100 T 次哈希运算。)
挖矿协议
然后是挖矿协议。在前面,我们解释了哈希率或者说挖矿是怎么会是,但在网络中,我们如何将这么多机器、矿场组织起来?这就有更多东西要说了。
目前,我们使用 “Stratum V1” 协议。我敢肯定你们都听过 “Stratum V2”,这是目前非常热的一个话题,不过已经有点超出这个演讲的范围了。我会在这里那里补充一点信息、告诉你两者的主要区别,但现在,你只需记住,我们讨论的是 Stratum V1 。
矿工和矿池通常只使用 TCP 连接。所以,在矿池,我们会打开一个 TCP 端口,供矿工连接,而通信形式是 JSON RPC(以 JSON 格式表达的指令)。这是非常直接的。消息的类型可以在屏幕上看到:mining.subscribe、mining.authorize、mining.set_target、mining.notify 和 mining.submit。这几乎就是 Stratum 协议的全部了。它是非常简单的。我还增加了一些背景知识在这儿。
“订阅(subscribe)” 是双方要完成的第一件事,这就像是,矿工表示:我在这儿,我已经准备好挖矿了,请在你的矿池里给我登记,并给我一个工作 ID 。同时,它也开始发送 extranonce 信息。这是 Stratum 协议的非常重要的部分,在它刚刚出现的 2013、 2014 年,真的是一项创新。(顺带说一句,Stratum 协议的其中一位作者也坐在观众席中)。好了,有了 extranonce 信息,我们就能将矿工需要用矿机完成的绝大部分工作都本地化,不需要跟矿池来回通信。这能够节约许多开销,如果你每迭代一次 PoW 运算都要跟矿池通信、获得信息,那就不得了了。所以,矿池发回 extranonce 信息,然后说,你就从这里开始,然后自己迭代运算。这就是矿工开始订阅的时候,双方的通信往返。
另一件事情是 “授权(authorization)”。你在矿池登记了一个 “员工(worker)”,这个员工有了一个矿池账户,但是你可能有许多个员工,每个都对应着多台机器。所以,当你授权一个员工时,你相当于是说,我的这个员工已经准备好接受任务了。这是在客户端和服务端之间发生的 —— 所谓客户端,我们说的是实际挖矿的机器 —— 然后矿池会发回共享的难度目标。
在矿池里面,我们根据 “shares(份额、分数)” 来组织挖矿,它的基础是将难度设定在网络所要求的挖出新区块的难度试下。基本上,要为每一台机器设置不同的难度,这样矿池才能每 2 ~ 5 秒收到机器的一个 share 。矿池基本上就是在跟矿机说,你有多少哈希率?好,你大概有这么多,那么我会为你设置难度,也许是 1 或 2,这样我每隔 2 ~ 5 秒就能从你这里得到一些信息。它会调整,对吧?那这有没有用呢?当然有用。
矿机知道了自己要挖矿的难度之后,它将需要获得实际用于挖矿的信息。这些信息就是之前我们解释过的那些 —— 需要放在区块头中的信息。
矿机需要独自处理的主要事情就是在这个 extranonce 字段上挖矿。它得到的主要信息,就像我在 “订阅” 部分说的,extranonce1 和 extranonce2_size 。extranonce1 是一个固定的变量,而 extranonce2_size 是可以由具体的一台矿机来迭代的是 extranonce 字段的长度。然后,矿机获得了 coinbase 交易的开头,就是矿池接收挖矿奖励的地址;然后是 coinbase 交易的结尾,就是一些额外的信息(或者说填充物)。 矿机就会迭代这个 Extranonce2 字段,直到找到一个目标哈希值,或者说一个输出哈希值,它低于 share 的难度目标。具体做法是将这些字段前后拼接起来(coinbase1 + extranonce1 + extranonce2 + coinbase2),然后将它们(跟其它交易)层层哈希成默克尔根。在每一个区块中,它的 coinbase 交易都是这个默克尔树最左边的叶子。为了计算默克尔根(Merkle root) —— 这就是 Stratum V1 和 Stratum V2 的主要区别,在 V1 中,你不会得到完整的树,你只会得到一些分支,凭借这些分支,你可以计算出这个树根。你已经有 coinbase 交易了,那么矿池会给你这笔交易,从而你们能计算出它们的哈希值;然后你会得到跟它相邻的这个哈希值,从而计算出再上一层的哈希值;以此类推,最终你会计算出 Merkle root,它显然是你的服务字符串中最重要的部分。
就这样,你能算出一个 Merkle root,你会不断(修改 coinbase 交易从而)不断迭代它,然后将其余元素加进去、形成一个区块头。当你找到一个 share 要求的哈希值,你的软件会把它发给矿池。然后是等待凭借这些 shares 获得支付。循环往复。
理解矿池
然后是矿池。我不会讲完这一整张图,但它确实总结了矿池的方方面面,这张图会放到 Revlit 上,各位如果想引用它,悉听尊便。
【听众因为图片在矿池的处理中心使用 “KAFKA” 字样而提出疑问,作者解释这只是一种软件,各家矿池可能有所不同。不译】
矿池的清账模式
矿池有许多种清账模式。得到使用的两种主要模式是 :PPLNS,根据最新一定数量的 shares 给矿工清账; FPPS,每一个 share 都得到完全支付。
主要区别在于,在 PPLNS 中,每当矿池找到一个区块,你(矿工)就会得到支付。比如说,Braiins(曾用名 “Slush Pool”)就使用这种模式。每当矿池找到一个区块,那么就根据在找到区块之前发放给矿工的最后一些 shares,来衡量他们为找到这个区块而贡献的哈希率,然后给他们支付。只考虑最新一批 shares 的部分原因是不希望矿工切换矿池 —— 只有在找到区块的这段时间里在矿池挖矿的矿工,才会得到奖励。
至于 FPPS,你得到保证,基本上,只要矿池没有破产,你的 shares 都会得到支付。所以,无论你一天生产了多少 shares ,你都能凭借自己生产的 shares(或者说你给矿池作的贡献),从流动性池子中获得支付。这跟矿池有没有找到区块无关。
清账风险
想必各位都会马上提出一个问题:要是这个矿池,一天里面没有找到任何区块,那会怎么样呢?连续两天、三天,更长时间 …… 那在 FPPS 矿池里面要如何清账?没什么,这就是运行一家 FPPS 矿池的风险 —— 你可能不得不先给矿工清账,而不会立即获得足够多比特币来覆盖你的之处。相反,在 PPLNS 矿池中,你基本上是把风险推给矿工。你连续几天挖不倒区块也没关系,矿池只会在挖出区块的时候给矿工支付。矿池实际上是不承担风险的,矿工不得不承担连续几天得不到付账的风险。
矿池风险的案例
【听众】:有没有哪个矿池是真的破产的呢?
有。不过后来他们被一家更大的矿池收购了。或者说,一家金融机构介入了,基本上接管了,也付清了账单。我这说的是 “Poolin”,他们把一部分矿池资金跟自己做的部分 DeFi 投资混在了一起。所以当 “三箭资本(Three Arrows Capital)” 倒下的时候,他们的许多矿池资金是跟投入 DeFi 协议的资金绑定的。一夜之间,Poolin 的所有矿工应得的收益都变成了比特币欠条 —— 这是站在矿池的角度说的。如果是从用户的角度看,那就像是,你说 “我想取出自己的比特币”,结果对方说 “不不不,现在你只能得到比特币欠条”。这是一个典型的案例。我也曾在矿池工作,讲出这个案例没有恶意。
挖矿市场
好了,到了本场演讲的主菜了,这些围绕挖矿的市场是怎么运作的?出现了矿池之后,本质上,矿池就是一种市场,你拥有哈希率,你把它卖给矿池;矿池反过来,利用汇集起来的哈希率来挖矿,然后根据哈希率的比例来分发收益给矿工 —— 这就像一种市场。那我们能不能再往前走一步呢?
挖矿硬件的进步
这个想法是原创的,来自比特币白皮书:PoW 本质上是一个 CPU 就能投一票。中本聪最初是这么认为的。但能用 CPU 来挖矿的日子已经过去很久了。我们很快就从 CPU 转向了 GPU(图形计算芯片),然后几乎同一时间出现了 FPGA(现场可编程门阵列)挖矿,最后,出现了 ASIC(特定应用集成电路)。我认为(20)12、13 年就出现 ASIC 挖矿了。
现代挖矿行业的挑战
从那时候开始,你就需要购买非常专业、价格不菲的硬件来挖矿了。没办法用家用硬件来挖矿了。又过了几年,就算你买到了这样的专业硬件,还需要找到非常便宜的电力,才能赚到钱。即使你买到了 ASIC,放在家里,那也不会赚到太多钱。而且实际上不太可行,或者说很难长期持续。现在,甚至就算你拿到了非常便宜的电力,你也需要一定的规模以及大量基础设施,才能降低运营成本。所以现在,挖矿真的挺不容易的。即使对那些大矿工来说,也非常艰难。
显然,挖矿行业一直有非常强的中心化趋势,我们在 Twitter 上能看到这些新闻,而且我听说在比特币圈子里有许多的批评,因为现在,像 Foundry 和比特大陆(Bitmain)这样的矿池,可以轻松控制整个网络 70 ~ 80% 的哈希率。就只是两家而已,对吧。
当然,你是可以切换矿池的,而且,它并不必然成为比特币的一种生存威胁,但如果我们能够尝试分散这种风险,肯定会更好,对吧?而我说的风险,一大部分实际上是资本风险。今天,为了运行挖矿企业、获得一定的规模,你需要先投入非常非常多的现金。你可以去看任何一家公开的大型挖矿企业的资产负债表,你会发现他们的体量都非常大,是跟这些项目有关的设备和资本品的大买家。这不可避免会有很多债务,这在当前的市场上是非常弱势的,因为没有人愿意借钱给比特币企业,觉得这风险太高了,所以最终贷款的利率会非常高。也许你能找到一些新的贷款方式,比如使用 ASIC 来担保,Khnighted 公司就提供这样的贷款,在挖矿公司倒闭之后,他们可以拿到所有的矿机;但是他们没有地方能转卖这些矿机,因为恰逢这些公司都破产了。这样的事情在去年发生了很多,我相信你们都听说了。
基本上,矿工们没有很好的办法来对冲任何一种风险。没有矿工能够尝试和锁定收益的流动性市场。考虑到矿工的业务形式和电力的价格,这些收益会在接下来半年、一年、两年乃至三年里逐步产生。如果他们预测比特币价格会上涨、难度也可能增加,从而哈希率的价格会下降,那么他们本应可以订立一种金融合约,在一条递减曲线上锁定一个价格,每月付(假设)2% 或 3% 的期权费,然后在难度调整超过 1% 的时候行使合约权利。这样我的收益就锁定了。这样的合约在世界上所有其他主要的大宗商品上都有,但在比特币的挖矿行业没有。而且,作为一个矿工,尤其在我们处理这样的资本结构时,它是非常重的负担,负债率很高,这就让它成了非常难以成功的业务。
我们一直在思考这个问题,我们的其中一个想法是:也许我们是在错误的地方寻找流动性、在错误的地方分散风险。我们为什么要去找那些传统的金融机构?他们只想从贷款中尽可能多收钱。为什么我们不直接去找那些有限制资金的人 —— 我的意思是有比特币的人 —— 他们显然非常在意网络的安全性,也对网络安全性的分散化有兴趣。为什么我们不利用这些限制的资金来分散这种类型的安全风险呢?
你可能会认为,“托管矿机” 和 “云挖矿”也是这样的尝试;完全不是,不过我们可以放他们一马,在最宽容的意义上说是。给不了解的人解释一下,矿机托管是指,你买下一台矿机,然后别人会把它放在他们的矿场里面跑这台机器,他们会给你支付,或者将算力投入你指定的矿池。云挖矿,则是你买下一个带有时限的哈希率合约。就我所知,通常这些哈希率不会实际交付;但我也听说有例外。基本上,区别在于,在云挖矿里面,你不会买下一台机器,而只会买一些据说是让你可以挖矿的合约。 但通常来说,这对你而言都非常抽象。
所以,主要问题在于,这一切根本不符合我们在比特币中坚持的原则,对吧。你得到的是一个完全不对称的信任模式。你必须完全信任这个人:首先,你要先掏出一大笔钱,从一个自称是服务商的人那里来买矿机;你得信任这个人不会哄抬矿机的价格,因为完全是由他们 “代理” 的;你得信任矿场的运营者会维持运营;最后,你还得信任,哪怕价格下跌,或者出现了什么意外,你的矿机依然会为你服务。你什么选择也没有,对吧?你的矿机可能放在另外一个你听都没听过的国家,只有上帝才知道你在哪里挖矿。所以,通常,不需要很长时间,这场戏就会露馅。它要么是个骗局,要么是个彻底的骗局。
云挖矿,你几乎总是被宰。我从来没听过哪一份云挖矿合约是赚钱的。相反,通常你是血本无归。至于矿机托管,就像我说的,这是不对称的信任模式,每个人都能宰你,不仅如此,你还要承担溢价,他们在每一个层面都能吞你的钱。
所以,我们能够尝试和避免这些情形的办法是在矿工和买家之间建立直接的连接。直接尝试创建一个市场,双方是可以直接协商的。
在那之前,还要多讲一句,我们已经有了一些哈希率期货市场。FTX 去年已经推出了这样的市场。Luxor 推出了一个更加合规的市场,那是一种不可交割的期货(non-deliverable future),你可以说它是一种互换(swap),那就传统得多了。它们的问题在于,我们并没有看到很多流动性。而且再说一遍,我认为,他们有些走回去了。就像我说的,为什么要去找这些传统的金融机构借钱呢?他们通常根本不了解比特币,也没有任何激励去理解和尝试承担比特币的风险,他们只想着利用一个事实再多榨一些油水出来:你需要钱,又没有别人愿意借给你钱,所以我可以按照非常高的利率借给你。
当然,它还变成了这样一种局面:没有人真的尝试在传统金融市场上购买这些哈希率期权合约。其它考虑是:好了,如果你真的要求交付,那会怎么样?没办法真正交付给你呀。那么合约的持续期呢?在大部分时候,如果你到 NiceHash 和 Mining Regret tools 这样的市场去看,你会发现合约的持续期都非常短,所以,如果你只是想赌个涨跌,那是可以的,但它持续时间太短了,无法做到你买一个东西、放在那里让它自己运行这样。至于不交割的期货,或者或互换合约,你知道的,你只是在买一种传统金融工具,不是用代码来保障的东西。
【演讲者在经过提醒后表示自己会加快速度讲完。】
点对点的哈希率
所以,我们的模式是,我们建立了拍卖机制来发现价格。我们使用多签名脚本来给哈希率的卖家支付,而且支付只有在哈希率交付之后才会发送;我们通过一个代理(proxy)来交付哈希率。因此,我们可以看到最终交付了多少哈希率。
我们画了一些图来解释整个模式。所以,我们在中间帮助建立这样的小型合约;买家用底部的橙色画出,他们的资金放在链上的多签名钱包里;交付则是通过矿池账户来实现。所以,来自矿工的哈希率被投放到一个矿池,最终,当这个矿池挖出一个区块时,支付会进入一个矿池账户。然后,合约就会发挥作用。最后,你真的可以将资金从你的矿池账户转移到另一个地方。这样一来,我们就真的能够保证交付会发生,并且我们有一个代理,可以读到有多少哈希率交付给了这个矿池账户。
我们已经有一个样品在运行了,你可以使用这个 QR 码来注册,稍后我会再给一个链接。这基本上就是我们的模式的流程,不过,我们有一个事件驱动的系统,只要你一给我们发送支付,我们就切出一部分当前在别的地方挖矿的哈希率到你的矿池账户(你可以提前登记你的矿池账户)。
闪电网络
最后一页关于闪电网络。我们希望能够通过闪电网络来发送矿池支付。问题在于 —— 我不知道你们有没有听过 Jade(硬件签名器),它也可以运行哈希运算。这里的想法是,(当前的哈希率价格是)每 TH/s 价值 10 聪。我们能够通过闪电网络来发送这么小的支付码?我们能够让每一焦耳的热量、浪费的电力都变成哈希计算吗?目前,这是做不到的,但是通过闪电网络,也许可以。
问题在于,就像 Lisa 指出的,如果让矿池通过闪电网络给矿工付账,那会遇到非常严重的流动性问题,因为这是在同一个方向上不断流出资金,你会很快用尽这些通道的流动性,这不是闪电通道的理想工作模式。我们需要让支付在两个方向上流动。现在,使用我们的模型,流动性确实是双向移动的。我们让购买哈希率的付款一次性在一个方向上推过去,然后你每天得到哈希率交付、得到矿池支付,资金就是反方向流动。这样就可以平衡这些通道。
于是问题变成了,这些矿池在什么位置上、我们怎么纳入新的 coinbase 交易?这是一个 “通道拼接” 技术有望解决的问题,我们可以拼接一个新的 UTXO 到现有的通道余额中。最终关闭的状态跟合约条款上预计的状态只会有细微的差别。所以,我们假设你是一个买家,希望用百分之 x 的保证金来赌你自己赢,那么通道关闭的状态将反映你是赌赢了还是对手(矿工)赌赢了。
最后,另一种可能相对容易做到这件事的办法,是使用一个 Fedipool 而不是闪电网络。我这里就不再展开。同时,我们也希望加入 Nostr 协议。我们认为,使用静态的 ID 来发放支付是很有前景的。你们可以试试样品,这是 QR 码。希望我们在那里相见。
(完)