本章开始分析比特币的交易代码。首先看交易的数据结构
数据结构的代码文件位置在bitcoin/src/primitives中,文件名称transaction.h
在类CTransaction中
static const int32_t CURRENT_VERSION=2; //表示当前的版本信息。使客户端知道是那个版本的资料
static const int32_t MAX_STANDARD_VERSION=2; // 最大的版本信息
const int32_t nVersion: //设置的版本信息
const std::vector vin; //不定长的字节,交易输入
const std::vector vout; //不定长的字节,交易输出
const uint32_t nLockTime; //交易锁定时间(区块号)
上面这些参数被定义成常量,目的是在没有更新缓存hash值的时候,本地参数不会被意外修改。
1 版本信息
static const int32_t CURRENT_VERSION=2;
static const int32_t MAX_STANDARD_VERSION=2
const int32_t nVersion
前两个是静态全局变量
CURRENT_VERSION:默认的交易版本信息。0.13版本以前的代码是1,从0.14版本开始版本是2
MAX_STANDARD_VERSION:标准交易的最高版本,为的是兼容原来的版本。这个参数是从0.12的版本出现的。
nVersion:当前的交易版本,在初始化的时候,默认的初始值是 CURRENT_VERSION。
在Transaction.cpp中初始化这个值
CTransaction::CTransaction() : vin(), vout(), nVersion(CTransaction::CURRENT_VERSION),nLockTime(0), hash() {}
2 交易形式
交易形式主要有三种
1) 支付并找零
2) 多个输入一个输出
这相当于现实生活中将很多硬币和纸币零钱兑换为一个大额面钞。像这样的交易有时由钱包应用产生来清理许多在支付过程收到的小数额的找零。
3) 一个输入多个输出
这类交易有时被商业实体用作分配资金,例如给多个雇员发工资的情形。
3 UTXO
在介绍输入输出以前,先介绍一个比特币里的核心概念:
UTXO
比特币交易中的基础构建单元是交易输出。
交易输出是比特币不可分割的基本组合,记录在区块上,并被整个网络识别为有效。 比特币完整节点跟踪所有可找到的和可使用的输出,称为“未花费的交易输出”(unspent transaction outputs),即UTXO。用户的比特币“余额”是指用户钱包中可用的UTXO总和,而他们可能分散在数百个交易和区块中。比特币钱包通过扫描区块链并聚集所有属于该用户的UTXO来计算该用户的余额 。大多数钱包维护一个数据库或使用数据库服务来存储所有UTXO的快速参考集,这些UTXO由用户所有的密钥来控制花费行为。
一个UTXO可以是1“聪”(satoshi)的任意倍数(整数倍)。就像美元可以被分割成表示两位小数的“分”一样,比特币可以被分割成八位小数的“聪”。尽管UTXO可以是任意值,但一旦被创造出来,即不可分割。这是UTXO值得被强调的一个重要特性:UTXO是面值为“聪”的离散(不连续)且不可分割的价值单元,一个UTXO只能在一次交易中作为一个整体被消耗。如果一个UTXO比一笔交易所需量大,它仍会被当作一个整体而消耗掉,但同时会在交易中生成零头。例如,你有一个价值20比特币的UTXO并且想支付1比特币,那么你的交易必须消耗掉整个20比特币的UTXO,并产生两个输出:一个支付了1比特币给接收人,另一个支付了19比特币的找零到你的钱包。类似的,一笔比特币交易可以是任意金额,但必须从用户可用的UTXO中创建出来。用户不能再把UTXO进一步细分,就像不能把一元纸币撕开而继续当货币使用一样。用户的钱包应用通常会从用户可用的UTXO中选取多个来拼凑出一个大于或等于一笔交易所需的比特币量。
详细的解释请参见:UTXO详解
4 交易输入的数据结构
交易输入:被交易消耗的UTXO
交易输入被定义在类class CTxIn中。
1)Prevout
是指前一个交易的输出,也就是父交易。
COutPoint prevout;//前一个交易的输出
其中COutPoint是一个类:
class COutPoint
{
public:
uint256hash;//前一个交易的hash值,即父hash
uint32_t n;//4个字节,前一个交易输出索引好,从0开始
};
中包括两个字段:
uint256 hash;//前一个交易的hash值,即父hash
int32_t n;//4个字节,前一个交易输出索引好,从0开始
2) scriptSig
解锁脚本,通过密钥可以解锁这个交易输入(UTXO),并使用这个UTXO(J交易输出)
CScript scriptSig;//解锁脚本
3)nSequence
指定交易什么时候可以被写到区块链中。其参数设置下面在详细分析
uint32_t nSequence;//序列号,表示什么时候去执行这个交易
具体参数定义如下:
static const uint32_t SEQUENCE_FINAL = 0xffffffff;
//如果nSequence被赋值为这个值,交易立刻执行,nLockTime无效,无需考虑锁定时间和要到达那个区块号再执行
static const uint32_t SEQUENCE_FINAL = 0xffffffff;
//如果nSequence被赋值为这个值,交易立刻执行,nLockTime无效,无需考虑锁定时间和要到达那个区块号再执行
static const uint32_t SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<< 31);
//如果nSequence设置了这个标志为,交易序列号nSequence不是被锁定为相对时间staticconst uint32_t SEQUENCE_LOCKTIME_TYPE_FLAG = (1 << 22);
//如果nSequence设置了相对锁定时间,并且设置SEQUENCE_LOCKTIME_TYPE_FLAG值,则将已512秒为一个基本单位,否则将已一个区块为单位
static const uint32_t SEQUENCE_LOCKTIME_MASK = 0x0000ffff;
//如果nSequence设置了相对锁定时间,锁定时间依据sequence字段而定
static const int SEQUENCE_LOCKTIME_GRANULARITY = 9;
//区块生成时间。
4)scriptWitness
隔离见证。
CScriptWitness scriptWitness; //! Only serialized through
5 交易输出数据结构
交易输出:由交易创建的UTXO
交易输出的类在class CTxOut中
1)比特币数量
CAmount nValue;//比特币数量
CAmount定义在CAmount.h中,64bit,8个字节
typedef int64_tCAmount;
2)锁定脚本
CScript scriptPubKey;
//锁定脚本,锁定脚本对应输入脚本中的解锁脚本,在锁定脚本中,我们通过私钥对该交易输出进行锁定,当这笔交易作为其他交易的输入时,需要通过私钥来解锁,即通过前面输入交易中提到的解锁脚本来实现。
6 锁定时间
const uint32_t nLockTime;
//锁定时间定义了能被加到区块链里的最早的交易时间,在大多数交易里,它被设定为0,用来表示即可执行,如果锁定时间不是0,并且小于5亿,就被视为区块高度,意指在这个指定区块高度之前的交易没有被包含在这个区块链里。如果锁定时间设定为大于5亿,则它被当作是一个unix纪元时间戳(从1970年1月1日)以来的秒数,并且在这个指定的时间之前的交易没有被包含这个区块链里
/*********************以上就是交易过程中涉及到的数据结构***************************/
区块链研习社比特币源码研读班 electroman
以下是广告:
我们区块链研习社已创建“区块链研习社币圈交流”小密圈”,在小密圈中,我们将带领大家一起学习区块链的原理与投资,还将提供区块链基本原理解答、交易所注册与交易操作、ICO交易与操作、投资分析、风险分析等内容。