• 10.5 打包交易至区块
    • 10.5.1 创币交易
    • 10.5.2 Coinbase奖励与矿工费
    • 10.5.3创币交易的结构
    • 10.5.4 Coinbase数据

    10.5 打包交易至区块

    验证交易后,比特币节点会将这些交易添加到自己的内存池中。内存池也称作交易池,用来暂存尚未被加入到区块的交 易记录。与其他节点一样,Jing的节点会收集、验证并传递新的交易。而与其他节点不同的是,Jing的节点会把这些交 易整合到一个候选区块中。

    ​让我们继续跟进,看下Alice从Bob咖啡店购买咖啡时产生的那个区块。Alice的交易在区块 277,316。为了演示本章中提到的概念,我们假设这个区块是由Jing的挖矿系统挖出的,并且继续跟进Alice的交易,因 为这个交易已经成为了新区块的一部分。

    Jing的挖矿节点维护了一个区块链的本地副本。当Alice买咖啡 的时候,Jing节点的区块链已经收集到了区块277,314,并继续监听着网络上的交易,在尝试挖掘新区块的同时,也监 听着由其他节点发现的区块。当Jing的节点在挖矿时,它从比特币网络收到了区块277,315。这个区块的到来标志着终 结了产出区块277,315竞赛,与此同时也是产出区块277,316竞赛的开始。

    在上一个10分钟内,当Jing的节点正在寻找区块277,315的解的同时,它也在收集交易记录为下一个区块做准备。目前 它已经收到了几百笔交易记录,并将它们放进了内存池。直到接收并验证区块277,315后,Jing的节点会检查内存池中 的全部交易,并移除已经在区块277,315中出现过的交易记录,确保任何留在内存池中的交易都是未确认的,等待被记 录到新区块中。

    ​Jing的节点立刻构建一个新的空区块,做为区块277,316的候选区块。称作候选区块是因为它还没有包含有效的工作量证明,不是一个有效的区块,而只有在矿工成功找到一个工作量证明解之后,这个区块才生效。

    ​现在,Jing的节点从内存池中整合到了全部的交易,新的候选区块包含有418笔交易,总的矿工费为0.09094925个比特 币。你可以通过比特币核心客户端命令行来查看这个区块,如例10-3所示:

    例10-3 使用命令行检索区块277,316

    1. $ bitcoin-cli get blockhash 277316
    2. 0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4
    3. $ bitcoin-cli getblock 0000000000000001b6b9a13b095e96db41c4a928b97ef2d9\44a9b31b2cc7bdc4
    1. {
    2. "hash" : "0000000000000001b6b9a13b095e96db41c4a928b97ef2d944a9b31b2cc7bdc4",
    3. "confirmations" : 35561,
    4. "size" : 218629,
    5. "height" : 277316,
    6. "version" : 2,
    7. "merkleroot" : "c91c008c26e50763e9f548bb8b2fc323735f73577effbc55502c51eb4cc7cf2e",
    8. "tx" : [
    9. "d5ada064c6417ca25c4308bd158c34b77e1c0eca2a73cda16c737e7424afba2f",
    10. "b268b45c59b39d759614757718b9918caf0ba9d97c56f3b91956ff877c503fbe",
    11. ... 417 more transactions ...//这一行显示交易数量
    12. ],
    13. "time" : 1388185914,
    14. "nonce" : 924591752,
    15. "bits" : "1903a30c",
    16. "difficulty" : 1180923195.25802612,
    17. "chainwork" : "000000000000000000000000000000000000000000000934695e92aaf53afa1a",
    18. "previousblockhash" : "0000000000000002a7bbd25a417c0374cc55261021e8a9ca74442b01284f0569"
    19. }

    10.5.1 创币交易

    区块中的第一笔交易是笔特殊交易,称为创币交易或者coinbase交易。这个交易是由Jing的节点构造并用来奖励矿工们所做的贡献的。

    注意:当块277,316开采时,每个块的奖励是25比特币。 此后,已经过了一个“减半”时期。 2016年七月份的奖励为12.5比特币,2020年达到210000区块时,将再次减半。

    ​Jing的节点会创建“向Jing的地址支付25.09094928个比特币”这样一个交易,把生成交易的奖励发送到自己的钱包。Jing挖出区块获得的奖励金额是coinbase奖励(25个全新的比特币)和区块中全部交易矿工费的总和。

    如 例10-4所示:coinbase交易

    1. $ bitcoin-cli getrawtransaction d5ada064c6417ca25c4308bd158c34b77e1c0eca2a73cda16c737e7424afba2f 1
    1. {
    2. "hex" : "01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0f03443b0403858402062f503253482fffffffff0110c08d9500000000232102aa970c592640d19de03ff6f329d6fd2eecb023263b9ba5d1b81c29b523da8b21ac00000000",
    3. "txid" : "d5ada064c6417ca25c4308bd158c34b77e1c0eca2a73cda16c737e7424afba2f",
    4. "version" : 1,
    5. "locktime" : 0,
    6. "vin" : [
    7. {
    8. "coinbase" : "03443b0403858402062f503253482f",
    9. "sequence" : 4294967295
    10. }
    11. ],
    12. "vout" : [
    13. {
    14. "value" : 25.09094928,
    15. "n" : 0,
    16. "scriptPubKey" : {
    17. "asm" : "02aa970c592640d19de03ff6f329d6fd2eecb023263b9ba5d1b81c29b523da8b21OP_CHECKSIG",
    18. "hex" : "2102aa970c592640d19de03ff6f329d6fd2eecb023263b9ba5d1b81c29b523da8b21ac",
    19. "reqSigs" : 1,
    20. "type" : "pubkey",
    21. "addresses" : ["1MxTkeEP2PmHSMze5tUZ1hAV3YTKu2Gh1N"
    22. ]
    23. }
    24. }
    25. ]
    26. }

    与常规交易不同,创币交易没有输入,不消耗UTXO。它只包含一个被称作coinbase的输入,仅仅用来创建新的比特 币。创币交易有一个输出,支付到这个矿工的比特币地址。创币交易的输出将这25.09094928个比特币发送到矿工的比 特币地址,如本例所示的1MxTkeEP2PmHSMze5tUZ1hAV3YTKu2Gh1N。

    10.5.2 Coinbase奖励与矿工费

    为了构造创币交易,Jing的节点需要计算矿工费的总额,将这418个已添加到区块交易的输入和输出分别进行求和,然 后用输入总额减去输出总额得到矿工费总额,公式如下:

    1. Total Fees = Sum(Inputs) - Sum(Outputs)

    ​在区块277,316中,矿工费的总额是0.09094925个比特币。

    紧接着,Jing的节点计算出这个新区块正确的奖励额。奖励额的计算是基于区块高度的,以每个区块50个比特币为开始,每产生210,000个区块减半一次。这个区块高度是277,316,所以正确的奖励额是25个比特币。

    ​详细的计算过程可以参看比特币核心客户端中的GetBlockValue函数,如例10-5所示:

    ​例10-5 计算区块奖励—函数GetBlockValue, Bitcoin Core Client, main.cpp

    1. CAmount GetBlockSubsidy(int nHeight, const Consensus::Params
    2. &
    3. consensusParams){
    4. int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
    5. // Force block reward to zero when right shift is undefined.
    6. if (halvings
    7. >
    8. = 64)
    9. return 0;
    10. CAmount nSubsidy = 50 * COIN;
    11. // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
    12. nSubsidy
    13. >
    14. >
    15. = halvings;
    16. return nSubsidy;
    17. }

    ​变量Subsidy表示初始奖励额,值为 COIN 常量(100,000,000聪)与50的乘积,也就是说初始奖励额为50亿聪。

    紧接着,这个函数用当前区块高度除以减半间隔(SubsidyHalvingInterval 函数)得到减半次数(变量 halvings )。每 210,000个区块为一个减半间隔,对应本例中的区块277316,所以减半次数为1。

    变量 halvings 最大值64,如果超出这个值,代码算得的奖励额为0。

    然后,这个函数会使用二进制右移操作将奖励额(变量 nSubsidy)右移一位(等同与除以2),每一轮减半右移一次。在这个例子中,对于区块277,316只需要将值为50亿聪的奖励额右移一次,得到25亿聪,也就是25个比特币的奖励额。之所以采用二进制右移操作,是因为相比于整数或浮点数除法,右移操作的效率更高。

    ​最后,将coinbase奖励额(变量 nSubsidy )与矿工费(nFee)总额求和,并返回这个值。

    注意: 如果Jing的挖矿节点把coinbase交易写入区块,那么如何防止Jing奖励自己100甚至1000比特币? 答案是,不正确的奖励将被其他人视为无效,浪费了Jing用于工作证明的投入。 只有这个区块被大家认可,Jing才能得到报酬。

    10.5.3创币交易的结构

    经过计算,Jing的节点构造了一个创币交易,支付给自己25.09094928枚比特币。

    例10-4所示,创币交易的结构比较特殊,与一般交易输入需要指定一个先前的UTXO不同,它包含一个“coinbase“输 入。在之前的章节中,我们已经给出了交易输入的结构。现在让我们来比较一下常规交易输入与创币交易输入。表10-1给出了常规交易输入的结构,表10-2给出的是创币交易输入的结构。

    ​表10-1 常规交易输入结构

    10.5 打包交易至区块 - 图1

    表10-2,coinbase交易输入结构

    10.5 打包交易至区块 - 图2

    在Coinbase交易中,“交易哈希”字段32个字节全部填充0,“交易输出索引”字段全部填充0xFF(十进制的255),这两个字段的值表示不引用UTXO。“解锁脚本”由coinbase数据代替,数据可以由矿工自定义。

    10.5.4 Coinbase数据

    ​创币交易不包含“解锁脚本“(又称作 scriptSig)字段,这个字段被coinbase数据替代,长度最小2字节,最大100字节。除 了开始的几个字节外,矿工可以任意使用coinbase的其他部分,随意填充任何数据。

    以创世块为例,中本聪在coinbase中填入了这样的数据“The Times 03/Jan/ 2009 Chancellor on brink of second bailout for banks“(泰晤士报 2009年1月3日 财政大臣将再次对银行施以援手),表示对日期的证明,同时也表达了对银行系统的不信任。现在,矿工使用coinbase数据实现extra nonce功能,并嵌入字符串来标识挖出它的矿池,这部分内容会在后面的小节描述。

    coinbase前几个字节也曾是可以任意填写的,不过在后来的第34号比特币改进提议(BIP34)中 规定了版本2的区块(版本字段为2的区块),这个区块的高度必须跟在脚本操作“push“之后,填充在coinbase字段的起始处。

    ​我们以例10-4中的区块277,316为例,coinbase就是交易输入的“解锁脚本“(或scriptSig)字段,这个字段的十六进制值 为03443b0403858402062f503253482f。下面让我们来解码这段数据。

    ​第一个字节是03,脚本执行引擎执行这个指令将后面3个字节压入脚本栈,紧接着的3个字节——0x443b04, 是以小端格式(最低有效字节在先)编码的区块高度。翻转字节序得到0x043b44,表示为十进制是277,316。

    ​紧接着的几个十六进制数(03858402062)用于编码extra nonce(参见”10.11.1 随机值升位方案”),或者一个随机值,从而求解一个适当的工作量证明。

    ​coinbase数据结尾部分(2f503253482f)是ASCII编码字符 /P2SH/,表示挖出这个区块的挖矿节点支持BIP0016所定义的 pay-to-script-hash(P2SH)改进方案。在P2SH功能引入到比特币的时候,曾经有过一场对P2SH不同实现方式的投票, 候选者是BIP0016和BIP0017。支持BIP0016的矿工将/P2SH/放入coinbase数据中,支持BIP0017的矿工将 p2sh/CHV 放入他们的coinbase数据中。最后,BIP0016在选举中胜出,直到现在依然有很多矿工在他们的coinbase中填 入/P2SH/以表示支持这个功能。

    10-6使用了libbitcoin库(在之前“其他替代客户端、资料库、工具包”中提到)从创世块中提取coinbase数据,并显示 出中本聪留下的信息。libbitcoin库中自带了一份创世块的静态拷贝,所以这段示例代码可以直接取自库中的创世块数 据。

    ​例10-6 从创世区块中提取coinbase数据​

    1. code/satoshi-words.cpp\[\]

    ​例8-7中,我们使用GNU C++编译器编译源代码并运行得到的可执行文件,

    ​例8-7 编译并运行satoshi-words示例代码

    1. $ # Compile the code
    2. $ g++ -o satoshi-words satoshi-words.cpp $(pkg-config --cflags --libs libbitcoin)
    3. $ # Run the executable
    4. $ ./satoshi-words
    5. ^D��
    6. <
    7. GS
    8. >
    9. ^A^DEThe Times 03/Jan/2009 Chancellor on brink of second bailout for banks