如何储存
交易数据是用字节的形式存储在区块链中,但是我们分析和处理的时候一般使用16进制。另外BTC的数据都是通过小端模式存储的。
16进制:计算机的世界只有2进制,但是为了节省空间已经增加可读性,BTC使用了16进制的形式来保存数据。两位16进制 能表示 8位的2进制数据,一个字节的长度是 8位。所以两个16进制的数能表示一个字节。
小端模式:就是解析数据的时候,先出现的字节要放到数据的最后面。比如16进制的
151413
通过解析后应该是131415
。解析都是按照每个字节一个个进行的。
真实的交易数据
这是一个真实的交易信息
源数据的16进制表示
010000000181f46502fd3a9e7df61e409ace29acaba95130a041cd4467c299984d6849bd09010000006a47304402204300d701d7beb055b369955adf7fa39faedc2c0d1f1cd49b4c7e7913ac937d9c0220713f7f19b72e4399db2a1a627176c4a093db8ea72bb612dd949f3e0c0cf28a3c012103683ad7dd8a485e4be62e963d8f60cf51aca0652660b1ed8cf2b6b2a2e34631f0ffffffff01a0860100000000001976a9144d6567616e264769616e6e69466f72657665722188ac00000000
数据格式
我们把上面的数据先进行一下分割并添加说明:
01000000 # 前4个字节 表示 版本号
01 # 第5个字节 表示 有几个输入,使用VanInt表示
81f46502fd3a9e7df61e409ace29acaba95130a041cd4467c299984d6849bd09 # 第 6-37 位 表示 第1个输入的前一笔交易的哈希值(也称为散列值)
01000000 # 第38 - 41 位表示 前一笔交易的输出索引(因为一个交易中可能有多个输出)
6a # 第42个字节表示 解锁脚本长度,这里转成10进制是106;此字段使用 VarInt 表示ScriptSig的长度,有时候可能不是一个字节(后续文章介绍)
47304402204300d701d7beb055b369955adf7fa39faedc2c0d1f1cd49b4c7e7913ac937d9c0220713f7f19b72e4399db2a1a627176c4a093db8ea72bb612dd949f3e0c0cf28a3c012103683ad7dd8a485e4be62e963d8f60cf51aca0652660b1ed8cf2b6b2a2e34631f0 # 这 106 个字节就是解锁脚本
ffffffff # Sequence(后续文章介绍)
01 # 表示有一个输出,使用VanInt表示
a086010000000000 # 表示输出金额,按照小端法转成10进制是 100,000 单位是 satoshi,也是 0.001 BTC
19 # 表示 锁定脚本长度,转成10进制是 25,此字段使用 VarInt表示
76a9144d6567616e264769616e6e69466f72657665722188ac # 锁定脚本
00000000 # 表示锁定时间:多久之后这个输出才能被写入区块。
使用表格整理
数据项 | 英文名 | 长度 | 16进制表示的源数据 | 重新组装好的数据 | 可读数据 |
---|---|---|---|---|---|
版本号 | Version | 固定4字节 | 01000000 | 00000001 | 版本号1 |
输入数量 | Input Length | 不固定,1字节 | 01 | 01 | 有1个输入 |
第一个输入的前一笔交易的哈希 | Pre Trade Tx | 固定32字节 | 81f46502fd3a9e7df61e409ace29acaba95130a041cd4467c299984d6849bd09 | 09bd49684d9899c26744cd41a03051a9abac29ce9a401ef67d9e3afd0265f481 | 上个交易链接 |
锁定脚本长度 | ScriptSig Size | 不固定,当期是1字节 | 6a | 6a | 输出脚本有106字节 |
锁定脚本 | ScriptSig | 不固定,当前106字节 | 47304402204300…34631f0 | 之后文章详解 | 之后文章详解 |
序列 | Sequence | 固定长度,4字节 | fdffffff | 之后文章详解 | 之后文章详解 |
输出数量 | Outputs Length | 不固定,1字节 | 01 | 01 | 有1个输出 |
金额 | Value | 固定长度,8字节 | a086010000000000 | 00000000000186a0 | 转账金额是10,0000 |
锁定脚本长度 | Script Size | 不固定,1字节 | 19 | 19 | 25 |
锁定脚本 | Script | 不固定,25字节 | 76a9144d6567616e264769616e6e69466f72657665722188ac | 之后文章详解 | |
锁定时间 | LockTime | 固定长度,4字节 | 00000000 | 000000000 | 表示立即可用 |
分析脚本分享
from bitcoin.core import CTransaction, b2lx
def print_transaction_info(tx):
print("Transaction Information:")
print(f" Version: {tx.nVersion}")
print(f" Inputs ({len(tx.vin)}):")
for i, txin in enumerate(tx.vin):
print(f" Input {i + 1}:")
print(f" Previous Tx Output: {b2lx(txin.prevout.hash)}:{txin.prevout.n}")
print(f" ScriptSig: {txin.scriptSig.hex()}")
# 获取witness
witness_data = tx.wit.vtxinwit[i].scriptWitness.stack if tx.wit.vtxinwit else None
if witness_data:
print(f" Witness (SegWit): {witness_data}")
print(f" Outputs ({len(tx.vout)}):")
for i, txout in enumerate(tx.vout):
print(f" Output {i + 1}:")
print(f" Amount: {txout.nValue / 100000000} BTC")
print(f" ScriptPubKey (hex): {txout.scriptPubKey.hex()}")
print(f" Lock Time: {tx.nLockTime}")
# 输入你的原始交易数据
raw_transaction = "010000000181f46502fd3a9e7df61e409ace29acaba95130a041cd4467c299984d6849bd09010000006a47304402204300d701d7beb055b369955adf7fa39faedc2c0d1f1cd49b4c7e7913ac937d9c0220713f7f19b72e4399db2a1a627176c4a093db8ea72bb612dd949f3e0c0cf28a3c012103683ad7dd8a485e4be62e963d8f60cf51aca0652660b1ed8cf2b6b2a2e34631f0ffffffff01a0860100000000001976a9144d6567616e264769616e6e69466f72657665722188ac00000000"
# 将十六进制字符串转换为字节数组
raw_transaction_bytes = bytes.fromhex(raw_transaction)
# 使用CTransaction解析交易数据
tx = CTransaction.deserialize(raw_transaction_bytes)
# 打印交易信息
print_transaction_info(tx)
整理
-
源码地址
-
参考的交易地址
-
交易的详情
-
交易源数据
-
上个交易链接