比特币源码研读-交易

0x00 废话

距离上次开篇已有半个多月了,平时晚上回家又懒,周末回家还要带娃,研读代码工作进展很慢,趁今天出差的路上又对代码梳理了一下,趁热赶出这篇文章。热情还在,只是对自己要求在降级,从产出高质量的文章,降级到但求没有错误(最怕误人子弟啊)。调试环境已从linux上gdb降级到windows上的 visual gdb;为了能一睹作者最初的设计思想,版本号也从0.14降级到0.8,隔离见证以及闪电网络的研读部分暂时不在范围之内。废话不多说,今天我们研读一下比特币的核心部分---交易。

0x01 UTXO

在比特币交易中有一个非常重要的概念UTXO(Unspent Transaction Output),也就是说比特币用UTXO取代了传统的账号系统。这句话如何理解呢,我们做个对比就知道了。假设A,B2位矿工分别挖到区块,获得coinbase奖励25btc,然后均转给C,C又转15个BTC给D。那么传统的账号系统,如下图:

UTXO的流通方式如下:

做过数据运维的朋友可能会说,UTXO不就是数据库里的日志表嘛?此话不假。我们知道银行或是其他的类似系统,不仅要对数据结果做落地入库,还要对交易记录做严格的管理,一旦发现数据异常,就要通过交易记录逐笔分析。所以严格意义上的讲,数据结果表是冗余的,因为结果是可以通过过程演算出来的,而且记录更容易查到那些作弊的人。当然记录推算结果也是要付出代价的,比如要消耗大量的计算,同时对记录的完整性有非常高的要求,不能有任何一条记录出错,否则全盘出错。比特币经过去中心化的分布式存储,以及共识机制的改良,把UTXO的思想发挥到了极致。

我们再来看一下master bitcoin的书中对UTXO的描述:

比特币交易的基本单位是未经使用的一个交易输出,简称UTXO。UTXO是不能再分割、被所有者锁住或记录于区块链中的并被整个网络识别成货币单位的一定量的比特币货币。比特币网络监测着以百万为单位的所有可用的(未花费的)UTXO。当一个用户接收比特币时,金额被当作UTXO记录到区块链里。这样,一个用户的比特币会被当作UTXO分散到数百个交易和数百个区块中。实际上,并不存在储存比特币地址或账户余额的地点,只有被所有者锁住的、分散的UTXO。“一个用户的比特币余额”,这个概念是一个通过比特币钱包应用创建的派生之物。比特币钱包通过扫描区块链并聚合所有属于该用户的UTXO来计算该用户的余额。

0x02 Transaction

下面我们来分析UTXO中的TX,TX就是transaction的缩写。CTransaction有两个重要的成员变量std::vectorvin和std::vectorvout,交易输入和交易输出。看下面的类关系图更会一目了然。

(上图有个笔误,CTxOut中的scriptPubKey应该是锁定脚本)对应的数据库序列化如下:

普通交易输入(CTxIn)

普通交易输出(CTxOut)

交易(CTransaction)

创世coinbase

CTxIn类代码,不难,不做过多注释

CTxOut类代码,不难,不做过多注释

CTransaction类代码,部分注释

关于锁定时间的解释如下:

交易的锁定时间锁定时间定义了能被加到区块链里的最早的交易时间。在大多数交易里,它被设置成0,用来表示立即执行。如果锁定时间不是0并且小于5亿,就被视为区块高度,意指在这个指定的区块高度之前,该交易没有被包含在区块链里。如果锁定时间大于5亿,则它被当作是一个Unix纪元时间戳(从1970年1月1日以来的秒数),并且在这个指定时点之前,该交易没有被包含在区块链里。锁定时间的使用相当于将一张纸质支票的生效时间予以后延。

0x03 交易流程

在熟悉交易的数据结构后,我们再来看一下交易流程:

具体的步骤如下:一、构造交易钱包类CWallet的CreateTransaction函数创建交易。主要分3步:1、填充交易的输出交易(vout)创建交易时,指定输出交易的信息,主要是输出的脚本(地址构造成CScript)、输出的币数量(nValue)。

2、填充交易的输出交易(vin)先从钱包的交易信息中选择合适的比特币(SelectCoins函数),填充到交易的输入交易中。3、签名(CTxIn.scriptSig)对输入交易的scriptSig签名(SignSignature函数)。由新的交易信息、私钥计算哈希值(SignatureHash函数),填充到输入交易的scriptSig中(Solver函数)。构造交易完毕,再提交交易,发送出去。

二、发送交易当构造完交易,则提交交易(钱包类CWallet的CommitTransaction函数),发送出去。提交交易时,先把交易添加到钱包中,然后标记旧的比特币为已经花费,再添加到交易内存池中,最后把交易传播下去。

传播交易时(RelayTransaction函数),由交易信息的哈希值构造CInv,类型为MSG_TX,添加到每个节点的发送清单(vInventoryToSend)中,发送消息(SendMessages)时把节点中的发送清单中的交易信息以”inv”命令发送出去。

三、接收交易当节点接收到交易命令(”tx”)后,把交易信息添加到交易内存池中,且传播下去,详见ProcessMessage函数。

由于本人水平有限,文中难免有理解不透的地方,还请大家多多指教!

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180908G1N18P00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券