区块链学习2-比特币基本原理

警告
本文最后更新于 2020-11-11,文中内容可能已过时。

区块链里最基本也是最重要的几个概念是地址交易区块网络。比特币用地址来标识一笔交易的支出方和接收方。所有的交易最终需要被记到统一的账本(也就是区块链)上,而这个账本是通过区块确认并完成的。每一个新区块的产生,都会被打上时间戳(区块头里的一个字段,是真的时间,后面详细介绍),最终生成按照时间前后排列并加以记录的电子交易证明。每个独立节点之间又通过比特币网络来建立联系,这样就组成了一个去中心化、分布式的电子交易记录时间戳服务器系统。比特币通过构造这个分布式时间戳服务器来解决双重支付问题。

注:文章主体引自“张健. 区块链,定义为了金融与经济新格局[M]. 北京:机械工业出版社. 2016:162-177”,中间有补充和删减,补充都直接上了链接,所以文末就不放参考文献了。

1. 地址

比特币地址的生成步骤如下:

  1. 生成椭圆曲线私钥与公钥。
  2. 将公钥通过SHA-256哈希算法处理,得到32字节的哈希值。
  3. 对于得到的哈希值,通过RIPEMD-160算法来得到20字节的哈希值——Hash160。
  4. 把由版本号+Hash160组成的21字节数据进行双次SHA-256哈希运算,得到的哈希值的前4字节作为校验和,放置在21字节数据的末尾。
  5. 对组成的25字节数组进行Base58编码,就可得到地址。

 注:椭圆曲线算法私钥32字节,通过私钥可以算出公钥,公钥65字节,压缩后都有33字节,太长了,没法直接当地址

整个过程如下图所示,可以看出,地址是由公钥经过一系列哈希算法及编码算法得到的,所以,地址其实是公钥的另一种表现形式,可以理解为公钥的摘要。我们花费自己的资产时,要使用地址(公钥)对应的私钥做签名,然后发送给接收方地址(公钥)。更详细的地址生成描述见 比特币地址生成算法详解

2. 交易

在中本聪的白皮书里,比特币被定义为一个链式的数字签名串。每一位电子货币的所有者通过这样的方式将它转移给下一位所有者:对前一个交易和下一位所有者的公钥签署一个数字签名,并将这个签名附加在交易的末尾。收款人通过验证签名,就可以验证电子货币的所有者链条。交易的运作图如下。

这类交易体系的问题在于收款人很难校验之前的某位资产拥有者是否进行了双重支付(双花)。通常的解决方案是引入可信的第三方如银行来对每一笔交易进行检验,以防止双重支付。而如果想要排除第三方中介机构,那么交易信息就应当被公开,且需要整个系统内的所有参与者都有唯一公认的历史交易序列。收款人需要确保在交易期间系统内的绝大多数节点都认同该交易是首次出现。

2.1 交易结构

比特币的交易实质是转账。如果每一笔转账都需要构造一笔交易数据,那么显得比较笨拙。为了使得价值易于组合与分割,比特币的交易被设计为可以纳入多个输入和输出,即一笔交易可以转账给多个人。从生成到在网络中传播,再到通过工作量证明、整个网络节点验证,最终记录到比特币的区块链,这就是交易的整个生命周期。交易的本质是一个包含交易发送方、接收方、资产转移等相关信息的数据结构,其数据结构如下表所示。

字段描述大小
版本(Version)这笔交易参照的规则四字节
输入数量(In-counter)交易输入(TxIn)列表的数量1-9字节
输入列表(Out-counter)一个或多个交易输入不定
输出数量(Lock time)交易输出(TxOut)列表的数量1-9字节
输出列表一个或多个交易输出不定
锁定时间锁定时间4字节

从整体结构来看,交易中的两个主要单元字段就是交易的输入与输出。输入标识着交易的发送方,输出标识着交易的接收方及对发送方的找零,交易的手续费则是输入的总和与输出的总和之差。由于所有的交易输入必然是前面某笔交易的输出,所以交易最核心的字段是交易的输出。一笔交易的数据结构如下图所示。

2.2 UTXO结构

比特币系统是没有余额的概念的,它使用的是UTXO模型(Unspent Transaction Outputs,未使用过的交易输出)。UTXO是比特币交易生成及验证的一个核心概念。交易构成了一组链式结构,所有合法的比特币交易都可以追溯到前一个或多个交易的输出,这些链条的源头都是挖矿奖励,末尾则是当前未花费的交易输出。所有的未花费的输出即为整个比特币网络的UTXO。

比特币规定每一笔新交易的输入必须是某笔交易未花费的输出,每一笔输入同时也需要上一笔输出所对应的私钥进行签名,并且每个比特币的节点都会存储当前整个区块链上的UTXO,整个网络上的节点通过UTXO及签名算法来验证新交易的合法性。下图是比特币系统中交易输入输出的过程:

比特币的交易输入通常有3种,分别是标准输入(Standard TxIn)、花费挖矿奖励(Spend Coinbase TxOut)、产生挖矿奖励(Coinbase/Generation),下图分别描述了这三种交易输入的结构。

比特币的交易输出大致有两种,分别是标准交易输出(Standard TxOut)、挖矿奖励输出(Coinbase TxOut),下图分别描述了这两种交易输出的结构。

2.3 脚本

脚本是交易里另一个比较重要的技术。每一笔交易的每一项输出,严格意义上讲并不是指向一个地址,而是指向一个脚本。脚本类似于一套规则,它约束着接收方怎样才能花掉这个输出上锁定的资产。

交易的合法性验证也依赖于脚本。目前它依赖于两类脚本:锁定脚本与解锁脚本。锁定脚本是基于可变的模式,通过一段脚本语言来实现,位于交易的输出。解锁脚本与锁定脚本相对应,只有按锁定脚本的规则去解,才能花掉这个脚本上对应的资产,位于交易的输入。脚本语言可以表达出无数的条件变种。这也是比特币作为一种“可编程的货币”所拥有的特性。而解释该脚本是通过类似于编程领域里的“虚拟机”进行的,脚本分布地运行在比特币网络里的每一个节点上。 目前常用的比特币脚本主要分为两种,一种是普通的P2PKH类型(Pay-to-Public-KeyHash),即支付给公钥的哈希值是地址,接收方只需要使用地址对应的私钥对该输出进行签名,即可花掉该输出。另一种是P2SH(Pay-to-Script-Hash),支付脚本的哈希值。拿多重签名来举例,它要求该输出要有N把私钥中的M把私钥(M≤N)同时签名才能花掉该资产,它类似于现实生活中需要多把钥匙才能同时打开的保险柜,只是更加灵活。 比如在比特币中,P2PKH的脚本规则如下:

1
2
pubkey script op_dup op_hash160 <pubkeyhash> op_equalverify op_checksig
signature script <sig><pubkey>

P2SH的脚本规则如下:

1
2
pubkey script op_hash160 <hash160redeemscript> op_equal
signature script <sig> [sig] [sig...] <redeemscript>

在上述的两种脚本规则里,Pubkey script代表着锁定脚本,Signature script代表着解锁脚本。以OP_开头的单词是相关的脚本命令,也是“虚拟机”所能解析的指令。这些命令规则根据Pubkey script的不同来进行划分,也决定着解锁脚本的规则。 比特币中的脚本机制相对简单,只是一个基于堆栈的、解释相关OP指令的引擎,能够解析的脚本规则并不是太多,不能实现很复杂的逻辑。但它为区块链可编程提供了一个原型,后续的一些可编程区块链项目其实是基于脚本的原理发展起来的,比如,以太坊就深入强化了脚本机制,该脚本机制不再只包括简单的OP指令,而是支持脚本语言,该脚本语言可以通过“虚拟机”去执行。以太坊实现了一个支持图灵完备脚本语言的区块链平台。 脚本机制对于区块链来说非常重要,它类似于区块链技术提供的一个扩展接口,任何人都可以基于这个接口去开发基于区块链技术的应用,比如智能合约的功能。脚本机制也让区块链技术作为一项底层协议成为可能。未来很多基于区块链的颠覆性应用,都可能是通过区块链的脚本语言来完成的。

3. 区块

比特币网络中每个(挖矿)节点都基于已存在的最新区块生成下一个区块,同时将网络中未确认的合法交易包含进去。在完成工作量证明之后,将新的区块广播到全网,同时获得区块的奖励,这个过程就是将所有的交易打上时间戳标记的过程。由于只有最长链上的区块才能够获得奖励,这导致了所有的挖矿节点被利益驱使,形成唯一最长链的结果,从而达成记账系统共识的一致性,保证了整个体系的可靠与安全。而要了解这些过程,我们就必须先了解一下区块相关结构及区块链中所使用的相关技术与原理。

3.1 区块结构

比特币网络里合法的交易都会被打包成一个区块,包含到比特币的公开账本(区块链)里。区块由包含元数据的区块头和紧跟其后的交易列表组成。区块数据结构如下表所

字段描述大小
魔术码固定值 0xD9B4BEF94字节
区块大小用字节表示该段之后的区块大小1-9字节
区块头包含6个字段80字节
交易数量交易列表长度1-9字节
交易列表记录到区块的交易信息列表中不定

区块数据的核心示例结构如下图所示。

区块由区块头及该区块所包含的交易列表组成。区块头的大小为80字节,由4字节的版本、32字节的上一个区块的哈希值、32字节的Merkle Root Hash、4字节的时间戳(当前时间)、4字节的当前难度值、4字节的随机数等组成。区块所包含的交易列表则附加在区块头后面。比特币网络约定每个区块的第一笔交易是coinbase交易,这是一笔为了让矿工获得奖励及手续费的特殊交易。

3.2 Merkle Tree

区块包含的所有交易首先都会通过Merkle Tree算法生成Merkle Root Hash并存储至区块头的数据结构里。Merkle Tree算法是用来同步数据一致性的算法,它基于一组哈希值列表构建成一个树,树的根哈希值作为原始数据列表的摘要。Merkle Tree具有以下特点:

  1. 数据结构是一个树,可以是二叉树,也可以是多叉树。
  2. Merkle Tree的叶子节点的值是数据集合的单元数据或者单元数据的哈希值。
  3. Merkle Tree的非叶子节点的值是所有叶子节点值的哈希值。

区块中所使用的Merkle Tree算法的原理如下图所示。

3.3 时间戳服务器

为了实现一个点对点的电子现金系统,中本聪提出了“时间戳服务器”方案。时间戳服务器对以区块形式存在的一组数据实施随机哈希处理,加上时间戳,并将该随机哈希值进行广播。显然,该时间戳能够证实特定数据于某特定时间是的确存在的,因为只有在该时刻存在了,才能获取相应的随机哈希值。每个时间戳应当将前一个时间戳纳入其随机哈希值中,每一个随后的时间戳都对之前的一个时间戳进行增强(Reinforcing),这样就形成了一个链条(Chain)。

4. 网络

比特币采用了基于P2P(Peer to Peer)的网络架构。P2P是指位于同一网络中的每台计算机都是彼此公平、对等的,各个节点共同提供网络服务,不存在任何“特殊”(中心)节点。P2P网络通信本身并不是比特币独有的发明,在比特币之前就已经被应用于文件共享领域了。比特币被设计成一个点对点的数字现金系统,而P2P正好是这个理念的核心特征的反映,也是该特征的基石。抛开比特币客户端的钱包功能来看,运行在每一台机器上的比特币核心程序就是比特币P2P网络中的一个节点。每个节点之间互联,组成了比特币网络,保证了整个比特币系统的安全。

比特币网络的相关功能如下:

  1. 新交易广播到全网的节点,每个节点会收到交易消息。
  2. 每个(挖矿)节点将新交易收集到节点的内存,并组装成区块。
  3. 每个(挖矿)节点都尝试在自己的区块中找到一个具有足够难度的工作量证明。
  4. (挖矿)节点找到一个工作量证明,把有效的区块数据向全网进行广播。
  5. 当且仅当包含在该区块中的交易都是有效的,并验证其完成了工作量证明,其他节点才认同该区块的有效性。
  6. 其他(挖矿)节点表示接受该区块,并在该区块的末尾制造新的区块以延长整个区块的链条。

在比特币网络中,交易和区块信息的传播是通过洪水算法(Flooding Algorithm)进行的。简单地说,就是每一个收到信息的节点,向与它相连的所有节点推送该信息。下一个收到信息的节点继续这个过程,信息很快就会像洪水一样覆盖全网络。可见,传播速度是呈指数增长的。通常在一两秒内,交易或者区块的信息就可以传遍全网。

节点始终都将最长的链条作为正确的链条,在它的基础上持续工作并延长它。如果有两个节点同时广播不同的基于上一个区块的新区块,那么其他节点在接收到该区块的时间先后上将存在差别。在此情形下,它们将在率先收到的区块基础上进行工作,但也会保留另外一个链条,以防后者变成最长的链条。该僵局的打破要等到下一个区块(工作量证明)被发现,当其中的一条链条被证实为是较长的一条时,在另一条分支链条上工作的(挖矿)节点将转换阵营,开始在较长的链条上工作。 所谓“新交易的广播”,实际上不需要抵达网络中的全部节点,只要交易信息能够抵达足够多的节点,它们将很快被整合进一个新的区块中。而区块的广播对被丢弃的信息进行容错处理。如果一个节点没有收到某特定区块,那么该节点将会发现自己缺失了该区块,就会向较长链的节点发出下载该缺失区块的请求。 比特币网络中的矿工们不停地在最新的区块基础上构造下一个区块,通过算力竞争来争取记账权(将新区块写到比特币的区块链的机会),确认网络的转账交易,同时获取区块奖励。由于每一个区块都包含上一个区块的哈希值,通过这个前向的哈希值,区块以链条的形式进行相连,最终形成了由各个区块组成的记账系统——区块链。而确保这一切运转正常的正是我们接下来要讲的共识算法。

支付宝
微信
0%