1、比特币总述
比特币是一项针对数字货币,基于区块链技术的具体应用,其结合了多种不同的技术,建立了多种模型。如下图中,一个去中心化的比特币客户端需要实现基于p2p的网络模型,基于UTXO且有激励、分叉处理、共识机制的交易模型,以及基于密码学的底层数据结构和总体的区块链结构。
2、底层数据结构------**的生成、作用及管理
椭圆曲线加密算法(ECC)是一种非对称加密算法,该算法可以在不泄露私钥的情况下,利用公钥对数据进行验证,也就是“私钥加密、公钥解密”。该算法在群论的基础上,先定义点加运算,再定义数点的乘法运算,得到一个离散对数求逆难解的公式:K=k*G。其中K是公钥、k是私钥、G是椭圆曲线上的某一随机初始点。已知G(x,y),由k求K是容易的,而由K求k是难解的,根据这个特性,可以将公钥与他人共享而不会泄露私钥(现实中并非将公钥K共享,而是将公钥K的衍生物------比特币地址A共享)。
上图是公钥K衍生比特币地址A的流程图。可以看出,公钥K经过SHA256和RIPEMD160算法,即一次双哈希得到一个160bits输出的公钥哈希值,随后将这个公钥哈希值通过Base58Check方式编码得到一个最终的比特币地址。 由于得到的公钥是椭圆曲线上的一个最终映射点,因此公钥K由x,y值组成,长度为256+256位,会引起传输不便,因此不仅需要编码还需要压缩。
公钥常用的编码格式有:base58、base58check。
私钥常用的编码格式有:Hex、WIF、WIF-compressed。
公钥常用的压缩:只存储x坐标,忽略y坐标(已知椭圆曲线,由x再计算出y是简单的);未压缩公钥用04作前缀,压缩公钥以02、03作前缀,02或03的区别在于确定y坐标的正负号。
由私钥可以生成公钥及比特币地址,同时私钥可以用于对UTXO解锁(可以理解为,对自己将要使用的存款进行数字签名)。私钥需要保密,而且私钥的数量不少,因此需要有高效的私钥管理方法,这一功能由客户端实现,它类似于现实中的钱包功能。以下列出一些常见的钱包实现方式。(下文的BIP是Bitcoin Improvement Proposals,是比特币建议的计划)
非确定性(随机)钱包:这种方式又称JBOK(just a bunch of keys),意指“一堆私钥”,显而易见它就是从一开始生成一堆随机私钥,保存所有的副本,每个私钥只使用一次避免重复,必须经常备份以免丢失。这种方式并不被鼓励。
确定性(种子)钱包(BIP0032/BIP0044):这种方式从一个公共种子使用单项离散方程生成私钥。因此对私钥可以进行简单的管理备份,而对种子进行严格管控即可。常见的类型有“分层确定性钱包”,这种钱包的工作方式见下图。
3、区块链总体结构------区块、Merkle树
区块链实质上就是一种数据结构,和表树图一样。区块链上的每一个节点成为区块,区块中的元数据利用Google的levelDB数据库存储,每一个区块中的区块头经过一次SHA256哈希计算得到一个区块哈希值,可以唯一标识一个区块,同时区块头中的父区块哈希值指针字段数据指向上一个区块,从而将区块连成一条链,从区块顶端可以沿着父指针一直追溯到创世区块。这样来看,区块链就类似于一个垂直的栈。
区块链其实可以有两种检索方式:第一种是根据父指针逐个检索,第二种是在数据库中,另外存储区块的高度和区块哈希的键值对,利用区块高度检索。
区块的节点结构
区块头字段的所有元数据
Merkle根、Merkle树
对于交易而言,如果每一笔交易都完整存储,那么存储量会是巨大的,因此交易数据必须要有一种机制能实现压缩,同时又能维持安全性。如上图,一个区块的所有数据都分别哈希化,存储在叶子上,两两再一次哈希,直至生成一个Merkle根,该根用于存储在区块字段中,做到数据的压缩。另一方面,根据哈希的特性,叶子节点任一数据被改动过,都可以经过验证发现篡改。
Merkle树的平衡性:若交易数量为单数,可以通过复制不平衡的叶子节点,达到偶数后再构建Merkle树。
通过Merkle树,对交易进行验证:若上图中要对绿色节点的交易数据存在性进行验证,只需要一个绿色节点和四个蓝色节点的哈希值,就可以计算出Merkle根哈希,即可以和区块字段进行比较验证。这种方法的作用对于拥有巨量大小的区块数据的验证计算尤为重要。
Merkle树和简单支付验证(SPV):对于轻量级客户端,往往不会存储一整个区块链账本的所有区块数据,而是只存储区块头。这种轻量级的客户端在进行通信的时候,会建立起一个bloom过滤器,只接受含有自身需要的比特币地址的交易数据的区块,同时以Merkle_block消息的形式接收数据,Merkle_block中只含有区块头和Merkle根中的与目标比特币地址相关的哈希路径。这样极大地简化了轻客户端的负载,也保持了它对交易的验证能力。
4、交易模型------UTXO、输入输出结构及脚本
现实中,我们拥有100元,向商家支付90元购买商品,就剩下10元,90元归属商家,10元归属自己。在比特币中有少许不同。由于比特币区块链中,全网维护同一个完整的账本,因此区块链数据应当是包含所有的交易和资金归属的证明。在比特币中,财产归属不是通过记录“我有多少钱”来实现,而是通过“别人转了多少钱给我,我还没花出去”来证明个人对比特币的所有权。这种数据模型称为“UTXO”(unspent transaction output 未花费交易输出)。如下图,输入来自于各种消费者的消费,输出者表明这些比特币最终归属于哪些比特币接收者,但值得注意的是,输入总和往往是比输出总和高一点的,因为需要给创造该区块的人(矿工)一点交易费,劳务费。同时还有一种常见的情况,就是超额找零,此时输出者和输入者会重合。
总的来说,就是输入来源于每个产生交易的消费者,而输出归属于比特币接收者、找零、矿工。
钱包余额:一个用户的余额往往由客户端对区块链数据进行扫描,聚合所有该用户的UTXO来计算得出。
以下是区块中交易字段的每一笔单笔交易的数据结构。
交易的输入字段:简单来说,交易的输入是一个指向UTXO的指针,实际环境中通过调用比特币核心客户端的远程调用或者第三方应用接口来检索可用的UTXO。使用它需要包含一个解锁脚本来签名。输入的数据结构如下:
交易的输出字段:给某人发送比特币,实际上就是为对方的比特币地址注册新的UTXO,日后只能靠对方的比特币私钥才能解锁该UTXO。为对方注册新的UTXO同时还需要一个锁定脚本将该UTXO锁定。以下是输出的数据结构:
⽐特币交易脚本语⾔:也称为脚本,是⼀种基于逆波兰表⽰法的基于堆栈的执⾏语⾔。比特币核心客户端的源代码中,有五大标准脚本,分别为:P2PKH、P2PK、MS多重签名、P2SH、OP_Return,详细脚本知识可以阅览《Master Bitcoin》一书。
挖矿机制:挖矿的过程简单来说就是付出本地计算力,通过验证新的交易数据,同时完成一个复杂哈希计算问题,构造新区块向全网广播,并获得矿金(无中生有,类似于央行印刷新货币,书中称为创币交易,它的交易输入字段与普通交易字段结构不同,没有UTXO输入,只有coinbase作为输入)与区块中交易产生的交易费。
共识机制:区块链的共识机制是区块链的核心,它使得异步自发交互的去中心网络也能达到安全一致。从整体来看,它可以分成四个方面阐述:1、每个全节点对接收到的交易根据统一的标准进行独立的验证;2、挖矿节点付出算力,将新交易集合打包进本节点产生的新区块;3、每个节点对接收到的新区块进行检验并组装进区块链;4、每个节点对含分叉的区块链进行独立选择,选择工作量证明机制下工作量最大的区块链。
工作量证明机制(Proof Of Work):这个机制是数学问题,其目的在于提高夺得记账权的门槛。其过程如下:区块字段含两个独特字段------“难度目标”和“Nonce”,难度目标是一个开头为t个0的值,表示需要找到一个哈希值,其大小比开头为t个0(二进制位)还小的值,哈希计算需要输入和迭代,输入由text字符串和nonce变化值共同构成,并由nonce不断增加从而迭代调整输入。即:
outputHash = hash( text 拼接 nonce++ )
必须找到一个outputHash,其小于难度目标。
找到之后,将该nonce填入本节点构建的新区块nonce字段,并全网广播,供其他节点验证,验证只需要一次简单计算。
值得一提的是,难度调整脚本在比特币核心的源文件中定义,根据难度调整,区块链的货币发行速度得到调整。
分叉机制:对于存在网络延时且布局大的比特币网络来说,存在分叉在所难免,但是每个节点只需要独立地选择工作量证明累计最大的或链条最长的分支作为主链即可解决问题。该方式解决问题的过程如下系列图可见,同种颜色表示顶端同区块:
最终分叉区块链选择最长链条,得到完整区块链账本。
5、 网络模型------节点类型、协议
一个比特币区块链全节点包含以下所有功能,而不同的节点依据不同的功能所定义,类似于一个平台的插件插拔。
网络发现:接入P2P的区块链网络,通常需要建立8333端口上的TCP链接,发送包含基本认证内容的version消息开始握手通信。互换version消息建立连接后,新节点发送addr消息获知更多的对等体ip地址,以便连接到更多的相邻节点。如下图:
区块同步:建立连接开始,节点做的第一件事就是同步区块,发送getblocks消息向对等节点获取区块数据,对等节点向申请节点发送inv消息表明库存清单,发现未同步区块同时检查未到数据传输上限时,申请节点发送getdata消息申请获取确定区块,而对端成批发送区块信息过来。协议过程如下:
SPV同步协议:全节点同步区块时,整个区块同步,无法知悉具体交易,但是SPV轻节点只请求具体交易,因此有泄露隐私风险,因此使用Bloom过滤器,来挑选区块,隐藏具体地址信息。SPV节点同步区块头过程如下:
交易池:由于总体来看,区块链中的数据并非时时一致,因此一些最新的,具有不确定性的交易信息,需要存储在本地内存或者本地数据库(交易池)中,而不是直接加入区块链。 另外,有些节点还会维护一个孤立交易池,用于处理某些子交易比父交易更快传达本地的情况。如果孤立交易池的子交易匹配上了刚到达的父交易,那么它们会组成一个完整的交易,从孤立交易池移入交易池(级联重构)。以上这些交易是未确认交易,等待确认,而有些客户端会另外维护一个UTXO池,其中只包含已确认交易,这些都是可用比特币。