基于区块链比特币隔离见证的正确理解

科普一下比特币的区块链是什么,老手们可以直接跳过这一部分了。这里说的比特币,是2017年8月以前的比特币,后来分为了 有隔离见证的btc 和没有隔离见证的 bch 两条链。下面会有不少看起来很专业的东西,不过请放心,我不是专业的程序员,不会讲太深的。稍微理解一点比特币的架构和转账的方法,对理解隔离见证的骗局很有帮助。比特币链条大概是长这个样子:
我们可以看到几个区块(block),可以看到每个区块都有两个部分:一部分是虚线画出来的 prev.block 指向上一个区块,这部分我们叫它“区块头”,另外一部分是“区块主体” transaction,即这个区块里交易的信息。由于每个区块头都指向上一个区块的头,所以这个系统我们叫他区块链。再详细点看这个区块头:
prev-hash 是上一个区块的这4个信息合起来的hash 结果,timestamp 是目前的时间,有这两个的限制,矿工至少要收到上一个区块的区块头,才能开始挖下一个区块。tx_root 是这个区块的主体里所有交易的merkle root,如果有任何一个交易被改变,这个 tx_root 就会有变化。 如此,比特币的区块形成了一条不能被更改的链:加入这个 block11里面的 tx1被改变了,那他上面的 hash1就会变,tx_root 也就变了,这样 block11的4个信息合起来的 hash 结果会不一样,就和 block12的 prev_hash 断开了,block12就无效,以此类推。
支付脚本
区块链里的交易,大概可以理解为是 “a 地址转给 b 地址 xx 个币”,“b 地址转给 c 地址 xx 个币”这样的信息。如果 c地址收到了 xx 个币,但没有往外转,那这就会在 utxo 数据库里记一条:“c 地址还有 xx 币没花掉”。假如 c 地址是普通的1打头的比特币地址,要花掉这笔钱,就需要用到一个脚本,这个脚本是“b 地址转给 c 地址 xx 个币”时规定的,定了这笔钱要怎么才能被c 地址花掉。一般这个脚本是这样的两部分
scriptpubkey部分: op_dup op_hash160 《pubkeyhash》 op_equalverify op_checksig
scriptsig部分: 《sig》 《pubkey》
不会编程的朋友请不要害怕,不难看懂的。scriptpubkey部分有几个“操作码”,是 op 打头的,表示几种操作。《pubkeyhash》就是比特币地址的中间部分,不带开头的版本号1和末尾的几位校验码,这部分是对公钥进行 hash 的结果。scriptsig部分要由想转账的这个人提供,公钥《pubkey》,和用私钥对这笔交易的签名《sig》。由私钥可以推导出公钥,公钥可以推导出比特币的地址,这两个步骤都不能反推(在当今科技下)。如果一个人可以展示私钥对这笔交易的签名,又可以提供这个地址的公钥,那我们就相信这笔转账是他授权的,别人伪造不了。矿池收到了提供的交易,和交易的签名,要怎么验证呢?就是运行一遍上面的脚本,看看结果是不是“true”。如果结果是 true 那就算通过了。首先要把scriptsig里的东西“堆”起来,形成一个“堆栈”:
《pubkey》
《sig》
然后,就一个一个地执行scriptpubkey部分。先是一个 op_dup,这个是复制操作,这些操作都是对着堆栈的顶部操作。所以复制操作后堆栈变成了:
《pubkey》
《pubkey》
《sig》
然后是一个 op_hash160,是 hash160算法的操作,把堆栈顶部的《pubkey》变成了《pubkey hash1》:
《pubkeyhash1》
《pubkey》
《sig》
然后是《pubkeyhash》,把这个推进堆栈:
《pubkeyhash》
《pubkeyhash1》
《pubkey》
《sig》
然后是op_equalverify,是检查是否相等的操作,对着堆栈顶部的两个元素进行。如果提供的《pubkey》是没错的话,应该是一样的,操作后堆栈变成了:
《pubkey》
《sig》
最后一个操作码是op_checksig,检查这个签名《sig》和公钥《pubkey》是不是对的上,如果没问题,堆栈就清空了。任何一步出问题都会造成脚本报错,如果没出错,那脚本结果是 true,表示通过。
脚本能用的操作码还有很多,可以进行 if,else,add,sub,drop,swap等等等等。比如,b 地址给 c 地址转账的时候,在刚才的脚本开头,加上一个《expiry time》和一个操作码 op_checklocktimeverify,就可以制造一笔冻结款,c 地址里的这笔钱要经过特定时间后才能花,在到期之前op_checklocktimeverify会让脚本验证失败。
据“2009年就开始参与比特币开发”的 craig wright 的说法,如果有足够的操作码,比特币系统也是图灵完备的,也可以运行eth 那样的智能合约。但是,许多操作码在2013年被 core 禁用了(因为 core 开发者看不懂那些操作码有什么用),对脚本的限制也更多。bch 在2018年的开发路线图里就包含了修复操作码设计的部分。
如果,b 地址给 c 地址转账的时候,把脚本搞成这样:
scriptpubkey部分: 留空
scriptsig部分: op_true
那这个脚本就是永远都可以通过的,不需要提供任何信息。这笔钱谁来转出,怎么转出都是有效的,我们称这钱现在是 anyone-can-spend。这笔钱等于就是给了矿池,因为矿池最终决定谁的交易可以被打包进块。如果有人把自己的钱转入这么一个 anyone-can-spend地址,矿池肯定会把这笔钱打给自己。
这个anyone-can-spend的脚本,就是隔离见证(segwit)的基础。用这个脚本,转账的时候就不用在区块里提供签名了,签名被“隔离”到了区块链以外,故名“隔离见证”。虽然签名挪了地方,但是转账的话签名还是要给的,不然岂不是乱转账了。其实,用户该发送的信息没有少,矿池要验证的信息也没有少,区别只是在区块链里存的信息少了。由于区块被设置了1mb 上限,并且已经堵满了,如果交易在区块里占的空间小一点,就能多挤几个交易进这个1mb 块。隔离见证技术被吹嘘有1.7 x 的扩容效果,如果所有人的交易都用这种 anyone-can-spend的格式的话。现在问题来了,这样把签名信息挪出区块链,有什么好处?为什么不直接把1mb 上限放宽到2mb 呢?
软硬分叉之争
如上的疑问,就是扩容软硬分叉之争。因为 segwit 是一个所谓的软分叉,而提高区块大小会是一个硬分叉。在之前的文章里已经说过,其实这里面软硬分叉之争是个表象,本质上是路线之争:普及后,比特币是流通的币,还是流通币的结算层;是流通的币更去中心,还是结算层更去中心。软硬分叉其实都只是技术手段而已,真正最后的结果还是被人所控制的。
涉及到“共识层”的修改,就会形成“分叉”。共识的运行其实是两个半层面,一层是在有算力的节点(矿池),第二层是没有算力的全节点,还有简单支付验证的轻钱包 spv 我们算半层。软分叉的特点是“旧版软件还能认新共识”。硬分叉是“旧版软件不认可新版软件”。我们用下面一张图来看软硬分叉的情况。
在 block8区块之后,系统从 v1软分叉升级到 v2,这时:
算力层:
运行 v2的矿工(大多数算力)认为最长的有效链是上面的这一条。
运行 v1的矿工(少量未升级算力)也认为最长的有效链是上面的这一条,会放弃掉自己的 block9(v1)形成孤块,因为它不是最长了。而 v1矿工挖出的旧版本块不会被 v2矿工承认,这样,v1矿工不升级,就面临着不被承认的境况,矿机白白浪费电。
全节点层:
运行 v1和v2的全节点(无算力)都认为最长的有效链是上面的这一条。v1节点因为没有矿机而无经济损失。
spv 层:
运行v1和v2的 spv钱包都认为最长的有效链是上面的这一条。
总结来看,软分叉时,只要挖矿的节点需要升。如果不升级,会有经济损失。
对比一下,系统从 v1硬分叉升级到 v2,这时:
算力层:
运行 v2的矿工(大多数算力)认为最长的有效链是上面的这一条。
运行 v1的矿工(少量未升级算力)认为最长的有效链是下面的这一条,上面一条虽然长但是无效。这样,v1矿工不升级,就会和 v2形成两条并行的链。
全节点层:
运行 v2的节点(无算力)认为最长的有效链是上面的这一条。
运行 v1的节点(无算力)认为最长的有效链是下面的这一条,上面一条虽然长但是无效。
spv 层:
如果这个硬分叉是扩容1m到2m 的话,由于 spv 钱包不检查容量限制,所以不会因为容量而判某链无效。运行v1和v2的 spv钱包都认为最长的有效链是上面的这一条。如果这个硬分叉修改了挖矿算法或者难度调节算法,那么 spv 节点也会依新旧版本各自认各自的链。
总结来看,硬分叉时,不只要挖矿的节点需要升级,不挖矿的节点也要升级,spv看情况, 可能可以不用升级。如果一部分算力不升级,会被拆成互相不能转账的两种币,像现在的 btc 和 bch 一样。
这么看,软分叉是不是比硬分叉来得安全呢?如果担心有人因为不知道大家升级,或忘记及时升级的话,看起来软分叉可以预防比特币被莫名其妙分为两个币。但这种情况是不存在的好么?现在算力都在几个矿池手里,只要提前几个星期通知一下大家做好准备,完全不会出现“忘记升级”这种事。能出现“忘记升级”的只能是普通用户,普通没有算力的用户,对系统的运行也没有影响。bch 上的 daa 硬分叉(把难度调节算法更改为逐块调整)已经非常好地展示了这样的硬分叉,对普通用户的使用并不构成障碍。我们平时使用其他软件,也经常面临着不升级一下登陆不进去这样的情况,并不是什么要命的事情。core 开发组一直在妖魔化硬分叉,表示硬分叉会造成比特币分裂为两种币,影响市场稳定。其实有分歧造成的硬分叉拦不住(bch 分离出来),没分歧的硬分叉升级没危险(bch 难度算法调整),无视路线分歧硬说软分叉安全是没有理由的。
软硬分叉之争的结局:中间派的失败
在大家对硬分叉的安全性有质疑的时候,中间派试图用“合并分叉”这样的手段来调解。大致手法就是先用大家都认可安全的软分叉从 v1升级到 v1.5,然后在 v1.5里预埋硬分叉到 v2 的代码。这样,如果是有算力“忘记升级”,他的 v1会在升级到 v1.5的时候被孤立,但不会立刻形成2种币。等到 v1.5到 v2进行硬分叉升级的时候,由于是预埋的代码,自动运行的,不会“忘记”。没有鄙视程序员的意思,这是一种典型的“程序员思维”。软件是死的,人是活的。如果人要搞事情,用代码是限制不住的。
中间派的最后运行的方案是 segwit2x 方案,合并分叉 segwit 和2m 这两个升级,前一个是软分叉,后一个是硬分叉。这个方案在纽约得到了超过83%的算力的支持,纽约会议之后,中国矿业又内部约定:大家都运行 segwit2x 的软件,这个软件预埋了代码,在 segwit 激活后90天,自动激活2m 的升级。问题就来了,你如何知道别人运行的软件和你是一样的?除非是黑进矿池的服务器去,否则从外部完全不能判断别人会不会在3个月后进行2m 分叉。虽然代码是写了,但别人可以运行别的版本的软件,可以把那几行删掉,改掉,外人无从得知。反扩容派是倾向于要 segwit而不要2m,中间派是为了要2m 愿意妥协 segwit。当 segwit 激活 以后,中间派没法靠这2行代码来逼反扩容派进行2m 升级,分裂成2种币的结局依然是难免的。最后结果大家也看到了,中间派认怂取消掉了2m 硬分叉的计划。
从2016以来,为了不让比特币分成两种币,大家花了那么多的时间在开会谈判上,现在才明白过来:如果路线有分歧,没有技术手段可以防止比特币分成两种币,也没有技术手段可以督促其他方面参与或不参与一个硬分叉。
隔离见证软分叉(segwit)的危险
前面我们提到,隔离见证是一个软分叉,旧版依然可以兼容,在升级的时候可以预防“因为忘记升级而乱套”。这可以算一个非常模糊的优点,具体有没有用是很值得怀疑的。相比之下,这软分叉的缺点就要严重得多。还是画个图看一下:
从 block7开始,系统加入了 segwit 的功能。前面介绍脚本的段落里已经介绍过这种 anyone-can-spend 的地址,假如 block7里一个 segwit 交易,把币发到了一个任何人都可以花的地址 c 里面,签名放在了外面。假设 c 地址的拥有者,打算在 block8把钱花出去,发送币给地址 d,诚实的矿工会验证c用户的签名,安全性基本和以前是一样的。这里,读者可以可以看到,“这笔钱是不是 c 的”这个问题,要靠 block7下面挂着的那个小块 sig来回答。如果仅看block7的信息,得出的结论会是“这笔钱是无主的随便捡”。
众所周知这个 segwit 功能是一个软分叉,也就是说旧版软件依然会承认 segwit 版发出来的块,不用升级。旧版的软件根本就看不到 这个小块 sig。旧版钱包软件(全节点或 spv 钱包)看到这笔钱就是无主的,任何人都可以花的。好在算力一层是必须全部升级的,旧版钱包软件如果提出要转走这笔钱会被所有算力拒绝,只能眼睁睁地看着钱在那里无主地放着。旧版钱包不能正确地获得交易信息,仅仅是验证机制被绕过了,无法发现交易模型已经改变了。前面我们介绍过,区块链的一个特点就是,后一个区块依赖前一个区块的区块头里的信息,如果修改一笔交易,区块头会变化,会造成整个链条的失效。可是现在 segwit 的“外挂见证块”并不在这个链条里面,修改 sig 里面的内容是不会使链条失效的。如果我有算力,但不是 c 地址的拥有者,我无法提供地址 c 的签名,但我把地址 c 的钱转给自己,这个块一定会被其他矿池拒绝掉,因为他们验证了 sig 发现我并没有资格动这笔钱。可是旧版钱包(全节点或 spv 钱包),和新版的 spv 钱包(不验证和自己不相关的交易,只接收区块头),都不会发现,他们只会跟随最长的块,sig 的内容不影响有效与否。
因此,segwit 带来了一种新型的51%攻击。这种攻击我在之前的一篇回答里介绍过:
一般币的51%攻击:我在高度12345上发布一个交易,从 a 地址到 b 地址发送1000比特币。同时我用自己的压倒性的算力,重新挖出一条12344-12345-12346的链,不包含刚才的交易。这样 b 一开始以为我付款了,后来我付款的那个块被孤立了,最终成型的最长链里不包含我的支付。这也是为什么各大交易所都要求3个确认,6个确认,就是防止出现你发送币给交易所的交易被孤立。一般认为6个确认后就几乎不会出问题了。小额支付(几万美金以内)经常1确认甚至0确认(块不满的时候)也可以,因为对于小额交易你没有经济动力去攻击。小额没赚头,大额肯定会要求多个块的确认很难做到,也没赚头,并且攻击窗口就是交易发布后的那一两个小时,过去了就没法攻击了。所以至今比特币没有发生过真正意义上的 51%攻击。
sw 币的51%攻击:segwit交易带来了“anyonecanspend”地址,它实质上是一个空白的交易签名。这种交易的签名被挪移到了附加的见证块里,因此这个技术叫做“隔离见证”。当然,虽然这个交易的签名不在这里,矿池肯定还是会去附加的见证块里找出来核对验证。在大家都核对验证的情况下,安全性和以前是一样的。控制算力超过50%的矿霸矿池,可以直接放弃附加见证块的核对,并把anyonecanspend地址里的钱转给自己,然后孤立那些去核对见证块的矿池。由于 segwit 是软分叉升级,原来的那些没有 segwit 功能的 spv 钱包和全节点钱包还是可以用的,这些钱包也没有核对附加见证块的能力,这时候这些钱包都会认为矿霸的链是合法的最长链。和一般币的51%攻击巨大的区别就是:一般币的51%攻击只能退回自己的一笔支付,而sw 币的51%可以花掉别人账上的钱,而且这钱的数字是从 sw 激活起慢慢积累变多的。sw 运行的越久,sw 交易运用的越多,这笔钱的数量也就越大,有动力攻击的算力也就越容易找。参考资料:risk of segwit - mining cartels - nchain
软分叉可以在不惊动普通用户的情况下偷偷进行,上 segwit 功能是软分叉,关闭 segwit 功能也是软分叉,也可以偷偷地进行。一旦使用了 segwit 功能,把币放在了anyonecanspend地址里,就只能信任51%的算力不会去进行关闭 segwit 功能的软分叉。如果不使用 segwit 功能,把币放在“经典”的1字头地址里面,任何软分叉都不能让你失去这币,除非有绝大部分算力针对你的存币地址发动一个硬分叉,才能把这个地址里面的钱转给别的地址。显然这种硬分叉是无法成为主流的,估计中本聪也得不到这种待遇。放在1字头地址里的币就是你的币,只有你可以转走卖掉,别人都不行。放在 segwit 地址里的币,就要看矿业有没有诚信了,如果超过51%的算力发动取消 segwit 的软分叉,剩下的49%里必须有算力主动发起硬分叉才能甩脱51%算力的最长链,保住你的币。可是 目前 segwit 链的座右铭就是“we don’t hard-fork”,是不是有点尴尬?
有人会说,51%算力发起关闭 segwit 功能的软分叉是不可能做到的事情。这点我同意,但是也许你不需要51%算力来做到这事。如果我是捣乱矿池,占5%算力,我挖出一个块以后,签名 部分拖延1分钟再发出去,其他矿池敢不敢再这1分钟里以我这个块为基础挖下一个块?如果挖,一分钟以后收到 签名 的内容可能会发现这个块里有非法的交易,这一分钟就白挖了。如果不挖,一分钟以后 签名 内容是正常的,就浪费了一分钟。我只要用5%的算力捣乱,每天出几个块,就足以逼很多矿池修改自己的软件设定,在收到签名前就开始挖矿。捣乱矿池可以把 签名 渐渐拖更久,比如10分钟后才发,很少的算力就可以把严格验证 签名搞成成本挺高的事情。不验证签名的矿工收益更高,这在 segwit 以前的比特币上是不可能发生的事情,如今可能了。如果有30%的算力不验证附加的签名块,那我只要21%的算力就可以发动上述的 segwit 独有的51%攻击了。
隔离见证软分叉(segwit)无法扩容
core的开发者一直在宣传,说 segwit 可以带来1.3x,后来又说1.7x,又四舍五入到2x 的扩容效果。从交易数来看,2017年8月中旬激活 segwit 以来,每个块的交易数勉强突破了之前的高点2250,连1.1x 的扩容效果也没有。每个块2000+笔的交易能力是不够的,必须尽快改进,这一点上各派都没有异议。core 的开发者现在已经不提“ segwit 有立竿见影的扩容效果”这话了,着重宣传闪电网络。“小额交易走闪电几乎零手续费,大额结算上主链五十美金一笔”,这已经是 core 支持者的信仰宣言。
第二层交易网络
我们来简单对比一下bch 的“传统”单层模型,和闪电网络的第二层模型。
手续费方面:
以50美金一笔手续费的大额结算来计算(50美金就是今天的手续费水平),闪电网络开闭通道各需要一次交易,就是100美金的成本(闪电节点的成本没有计入)。如果平均每个通道结算时已经发生过1000笔交易,那每个交易的成本为10美分,勉强还属于比较低的手续费水平。要什么样的通道才能1000笔结算一次呢?以我的想象力,我只能想到这个是支付宝,银行或者地下钱庄的模型,把我的币充值锁进去慢慢花。交易所等机构之间大概更有用一些,对于普通用户其实是毫无作用。
按照每个块开闭2000次闪电网络通道(1m 的极限),每个通道1000笔交易来算,bch 的模型里,1000000笔交易差不多也就是500mb 区块。nchain 已经和 bitcoinunlimited 联合测试过1gb 区块,并没有很科幻。
安全方面:
segwit 的安全性问题已经是一个很好的反例了。区块链,或者说a chain of digital signatures,是中本聪的杰作,也是比特币和支付宝,银行,信用卡的根本区别。在比特币,现在的 bch 里,没有私钥谁也没法挪动你的钱,你必须有私钥才能把钱挪动到指定的地方。闪电网络虽然已经宣称进行过多轮测试,但“怎么保证通道内的交易公正不被修改”这个问题,依然没有清楚的回答。如果有哪位朋友有好的资料能够提供,不胜感激。从我目前的理解是,闪电通道内基本还是充值卡的模型,外加了通过多次交换签名来让双方对余额有共识,但如果双方有意或无意对余额有分歧,需要由 闪电节点来裁决。segwit 的问题又出现了:有人可以在没有你的数字签名的情况下挪动你的钱。
安全方面,这一篇文章值得看看:https://news.bitcoin.com/lightning-network-centralization-leads-economic-censorship/
技术方面:
刚刚其实都是我瞎编的,目前闪电网络完全没有如此大流量的公开测试,考虑到闪电通道内多次反复交换签名的设计,同等硬件瓶颈下闪电网络的交易容量堪忧。
结语
我在敲这篇文章的时候,btc 正在疯涨,bch 和其他所有币都被“抽血”而下跌。同时,btc 拥堵了17万笔交易没有确认,单笔手续费大约50美金。steam 宣布放弃比特币支付渠道,因为手续费太贵了没法用了。bitpay 宣布要投资支持比特币以外的各种币,也是因为手续费太高。
市场在短时间内是不理智的,这个混乱时间点上暴涨暴跌都不稀奇。如果说再过十年,市场上主流的是哪种币?一个挪动困难,安全性堪忧的 btc 真能保值十年吗?如今 btc 确实是有保值增值的功效,在过去几年里任何一个时间点,甚至过去几个月的任何一个时间点买入,到今天都是大赚。暴涨总是有头的,如果btc 不再暴涨,失去了支付渠道和商家支持的 btc 就没有上新闻的能力了,在投资者的圈子里,不再暴涨的btc也失去了增值保值的能力。如今加密货币都是新事物,严格意义上来说btc 也还没有进入公众视野,新闻里的 btc 只有暴涨,没有应用。这两年新入场投资加密货币的,都很少有只买 btc 的了,都是 eth等币搭配着投资,在币圈 btc 都不是那么大众化,终究是会淡出公众视野,变得越来越小众的。十年后能成为主流的币,一定是接下来几年能第一个真正进入公共视野的币,我猜这个币是bch。

使用数字万用表测量电源瞬态恢复时间
箱式变压器安装规范要求_箱式变压器送电步骤
学习python经常会碰到什么错误
智慧工厂管理平台搭建能源管控系统开发技术公司
iphone8发布会时间确定:iphone 8外观、配置、功能大升级,成本提高涨价成必须要8000起
基于区块链比特币隔离见证的正确理解
泰捷盒子性能如何,它的优缺点都有哪些
如何提升光伏电站发电量,可参考这几招设计思路
抢占标准主导地位,物联网联盟加速合作
ISP是什么,达摩院为什么要自研ISP图像处理器
新唐科技NuMaker-PFM-M453主板介绍
成像雷达芯片技术揭秘:Vayyar第一代RF片上系统进行拆解与分析
苹果全新iPadOS系统增加了哪些新功能
智能安防主要遇到以下三个发展难题
未来MCU市场的分类要重新改写?
现有的网络方案及不足之处
热电阻校验装置的特点_热电阻校验装置的工作条件
一位FPGA工程师的工作日常
梦幻华丽外观的荣耀90系列即将登场
无主灯爆火,传统照明企业如何实现逆势增长?易微联为你解答