(三) 区块链数据结构 – 交易 您所在的位置:网站首页 区块的组成部分 (三) 区块链数据结构 – 交易

(三) 区块链数据结构 – 交易

2024-07-14 10:48| 来源: 网络整理| 查看: 265

区块由交易组成。区块体中包含若干项交易数据。

交易

交易主要包含两类数据:交易输入和交易输出。- 交易输入用来指明钱的来源- 交易输出用来指明钱的去向

除了交易输入和交易输出外,交易中还包含版本号和锁定时间。交易数据的存储结构如下:

交易数据存储格式

交易对象中的各个字段含义如下:

字段大小描述version4个字节明确该笔交易参考的版本规则numInputs1-9个字节交易中包含的输入数量inputs不定长交易中包含的输入数据numOutputs1-9个字节交易中包含的输出数量outputs不定长交易中包含的输出数据lockTime4个字节交易锁定时间

注:如果锁定时间为0,代表立即执行,无需锁定。如果该值小于5亿,则代表区块链到达该高度前,交易不会被执行,如果该值大于5亿,则该值代表Unix纪元时间戳,交易在该时间之后执行。

核心代码 - 变量定义 // These are bitcoin serialized. private long version; //交易遵循的版本号 private ArrayList inputs; //交易的金钱来源 private ArrayList outputs; //交易的金钱去向 private long lockTime; //交易的锁定时间 核心代码 - 数据解析 //解析区块原始字节数据,构造交易对象 @Override protected void parse() throws ProtocolException { cursor = offset; version = readUint32(); //读取版本号 optimalEncodingMessageSize = 4; // First come the inputs. long numInputs = readVarInt(); //读取输入交易量 optimalEncodingMessageSize += VarInt.sizeOf(numInputs); inputs = new ArrayList((int) numInputs); //逐一解析输入交易对象 for (long i = 0; i < numInputs; i++) { //构造输入交易对象 TransactionInput input = new TransactionInput(params, this, payload, cursor, serializer); inputs.add(input); long scriptLen = readVarInt(TransactionOutPoint.MESSAGE_LENGTH); optimalEncodingMessageSize += TransactionOutPoint.MESSAGE_LENGTH + VarInt.sizeOf(scriptLen) + scriptLen + 4; cursor += scriptLen + 4; } // Now the outputs long numOutputs = readVarInt(); //读取输出交易量 optimalEncodingMessageSize += VarInt.sizeOf(numOutputs); outputs = new ArrayList((int) numOutputs); //逐一解析输出交易对象 for (long i = 0; i < numOutputs; i++) { //构造输出交易对象 TransactionOutput output = new TransactionOutput(params, this, payload, cursor, serializer); outputs.add(output); long scriptLen = readVarInt(8); optimalEncodingMessageSize += 8 + VarInt.sizeOf(scriptLen) + scriptLen; cursor += scriptLen; } lockTime = readUint32(); optimalEncodingMessageSize += 4; length = cursor - offset; } 交易输入

交易输入指明了交易的金钱来源。在比特币系统中,交易的金钱来源,并不来自于某一特定账户,而来自于其他人的输出。比如A和B分别转给C一笔金钱,则当C向D支付时,需要用A和B的输出作为输入。

交易输入中,存储了其关联的交易输出指针,同时还存储了该输出的解锁脚本。

交易输入结构如下:

交易输入存储格式

交易输入中,各个字段的含义如下:

字段大小描述hash32个字节关联输出所在的交易Hash地址index4个字节关联输出在其交易输出集合中的索引scriptLen1-9个字节解锁脚本长度scriptBytes不定长解锁脚本数据sequence4个字节序列号,暂未使用

注:只有解锁脚本正确,才能对输出进行消费。解锁脚本需要使用当前用户的秘钥进行签名,因此只有当前用户,能使用别人来的输出。

核心代码 - 变量定义 // Allows for altering transactions after they were broadcast. Values below NO_SEQUENCE-1 mean it can be altered. private long sequence; // Data needed to connect to the output of the transaction we're gathering coins from. //关联的交易输出 private TransactionOutPoint outpoint; // The "script bytes" might not actually be a script. In coinbase transactions where new coins are minted there // is no input transaction, so instead the scriptBytes contains some extra stuff (like a rollover nonce) that we // don't care about much. The bytes are turned into a Script object (cached below) on demand via a getter. // 脚本字节数组可能并不是实际的脚本,在创世区块中,没有输入交易,该字段可能存储其他数据。正常情况下,该数据会转换成脚本对象 private byte[] scriptBytes; 核心代码 - 数据解析 //通过区块的原始字节数据,构造输入交易对象 @Override protected void parse() throws ProtocolException { //构造该输入交易对应的输出(接收地址) //解析数据时,会解析出对应输出所在交易的Hash地址以及交易输出对应的索引值 outpoint = new TransactionOutPoint(params, payload, cursor, this, serializer); cursor += outpoint.getMessageSize(); int scriptLen = (int) readVarInt(); //读取脚本长度 length = cursor - offset + scriptLen + 4; scriptBytes = readBytes(scriptLen); //读取解锁脚本数据 sequence = readUint32(); //序列号,目前未使用 } 交易输出

交易输出指明了钱的去向,拥有该输出,并用私钥解密后,方可作为其他交易的输入,进行消费。

交易输出中,存储了支付的金额以及锁定脚本。交易输出的存储结构如下:

交易输出存储格式

交易输出中,各个字段含义如下:

字段大小描述value8个字节支付金额(单位为聪)scriptLen1-9个字节锁定脚本长度scriptBytes1-9个字节锁定脚本数据

注:只有接收者,通过秘钥加密生成解锁脚本后,方可继续使用该输出作为输入,继续消费。

核心代码 - 变量定义 // The output's value is kept as a native type in order to save class instances. //支付金额 private long value; // A transaction output has a script used for authenticating that the redeemer is allowed to spend // this output. //锁定脚本 private byte[] scriptBytes; 核心代码 - 数据解析 //解析交易输出数据,包含输出金额和锁定脚本(接收者可以解锁该脚本) @Override protected void parse() throws ProtocolException { value = readInt64(); //获取交易输出的金额 scriptLen = (int) readVarInt(); //锁定脚本的长度 length = cursor - offset + scriptLen; scriptBytes = readBytes(scriptLen); //锁定脚本的内容 }

上一篇:(二) 区块链数据结构-区块

下一篇:(四) 区块链数据结构 – 脚本



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有