比特币源码剖析(四)之核心数据结构
比特币源码剖析(四)之核心数据结构
Bitcoin justnode 10个月前 (03-13) 174浏览
区块的结构
字段 | 说明 | 大小 |
---|---|---|
Magic no | 魔术字,值为0xD9B4BEF9 | 4 字节 |
Blocksize | 表示区块的大小,单位是字节 | 4 字节 |
Blockheader | 包含6个字段:version,hashPrevBlock,hashMerkeRoot,Times,Bits,Nonce | 80 字节 |
Transaction counter | 区块中包含的交易数量 | 1 – 9 字节 |
transactions | 存放交易的列表 |
CBlock和CBlockHeader类
CBlock继承自CBlockHeader类,其中CBlockHeader类为区块头中的六个字段定义了六个成员变量,CBlock类定义了成员变量vtx,用于保存区块中的transactions。同时CBlock类中定义了BuildMerkleTree方法用来生成默卡尔树。
CBlockHeader类的定义如下所示,该类中包含6个成员变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
CBlock类定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
交易的结构
字段 | 描述 | 大小 |
---|---|---|
Version no | 版本号,值总是为1 | 4 字节 |
In-counter | input的数量 | 1 – 9 字节 |
list of inputs | 存放input的列表 | 不固定 |
Out-counter | output的数量 | 1 – 9 字节 |
list of outputs | 存放output的列表 | 不固定 |
lock_time | 交易的锁定时间 | 4 字节 |
CTransaction类是比特币交易的核心类,类的定义如下所示,该类中有两个vector变量vin和vout,分别存放CTxIn和CTxOut类型的数据。其中CTxIn是输入交易,CTxOut是输出交易。
CTransaction类的定义如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
|
CTransaction类中变量的组成如下图所示:
scriptSig和scriptPubKey的作用,请参考理解比特币脚本一文
假设有这么一系列交易:
1. 上图的三个交易都是单输入单输出交易
2. 每个『输入交易』『输出交易』中,都包含对应的『脚本』
3. 交易a,Alice转账给Bob;交易b,Bob转账给Carol;交易c,Carol转账给Dave
4. 当前交易的『输入』都引用前一个交易的『输出』,如交易b的『输入』引用交易a的『输出』
按照之前的说法,交易a中的『输出脚本』就是Alice为Bob出的数学题。那么,Bob想要引用交易a『输出交易』的比特币,就要解开这道数学题。题解是在交易b的『输入脚本』里给出的!Bob解开了这道题,获得了奖金,然后在交易b中为Carol出一道数学题,等待Carol来解…
所以说,下图中相同颜色的『输出』和『输入』才是一对题和解:
scriptPubKey和scriptSig的格式如下:
1 2 |
|
验证的时候,scriptSig先把签名和公钥压到栈里,之后OP_DUP复制一份公钥,那么现在栈里就是一个签名,两个公钥。接着用OP_HASH160计算栈顶公钥的hash,再压上一个交易的收款人的公钥hash值到栈,用OP_EQUALVERIFY比较两个hash值,相同就说明这个钱不是你无中生有来的。最后OP_CHECKSIG检查签名,说明这个钱的确是你花出去不是别人花出去的,因为只有有私钥的你才能签名。
下面的步骤形象的展示了验证的过程。每一步中只有一个栈,箭头表示栈状态的变化。
第一步、
第二步、
第三步、
第四步、
第五步、
第四和第五步是用来验证你的公钥是不是出现在别人的vout交易中。如果你的公钥出现在别人的vout中,说明你拥有这部分比特币。
第六步、
这一步是用来验证你的币是你自己花出去的,不是别人花出去的。因为你的公钥只能解密自己私钥加密的内容,而不能解密别人私钥加密的内容。
交易的签名和验证
签名: sign(交易的摘要,发送方私钥) => 签名
验证: verify(签名,发送方的公钥) 计算的结果是否等于交易的摘要
交易的发送方对交易进行签名的作用有两个:
1.证明自己认可这笔交易
2.矿工节点需要验证签名和公钥是否匹配,以保证这笔交易是自己花出去的,而不是别人。
参考:https://zhuanlan.zhihu.com/p/25461051
btc_parser
解析比特币的块文件的工具
钱包目录结构
块文件结构
在**.dat文件中,存储了比特币区块链的信息
比特币的块结构如下
大小(字节) | 名称 | 数据类型 | 描述 |
---|---|---|---|
4 | magic_number | uint32 | 总是0xD9B4BEF9,作为区块之间的分隔符 |
4 | block_size | uint32 | 后面数据到块结束的字节数 |
80 | block_header | char[] | block header |
varies | transaction_cnt | uint | 交易数量 |
varies | transaction | char[] | 交易详情 |
block header的结构如下
大小(字节) | 名称 | 数据类型 | 描述 |
---|---|---|---|
4 | version | int32_t | 版本号 |
32 | previous_block_hash | char[32] | 前一个block的hash值 |
32 | merkle_root_hash | char[32] | 区块内所有交易的merkle hash值 |
4 | time | uint32 | unix时间戳,矿工挖矿的时间 |
4 | nBits | uint32 | 该块的标题hash必须小于的值。难度 |
4 | nonce | uint32 | 随机值,用于产生满足难度的hash值 |
交易的结构如下
大小(字节) | 名称 | 数据类型 | 描述 |
---|---|---|---|
4 | version | uint32 | 交易版本号 |
varies | tx_in_count | uint | 交易输入数量 |
varies | tx_in | tx_in | 交易输入 |
varies | tx_out_count | uint | 交易输出数量 |
varies | tx_out | tx_out | 交易输出 |
4 | lock_time | uint32 | 锁定时间 |
交易输入的结构如下
大小(字节) | 名称 | 数据类型 | 描述 |
---|---|---|---|
32 | previous_output_hash | outpoint | 前置交易hash |
4 | previous_output_index | uint32 | 前置交易index |
varint | script_bytes | uint | 解锁脚本长度 |
varies | signature_script | char[] | 解锁脚本 |
4 | sequence | uint32 | *** |
交易输出的结构如下
大小(字节) | 名称 | 数据类型 | 描述 |
---|---|---|---|
8 | value | int64 | 花费的数量,单位是聪 |
1+ | pk_script_size | uint | pubkey脚本中的字节数量 |
varies | pk_script | char[] | 花费这笔输出需要满足的条件 |