- 表格
大小 字段 描述 4字节 版本 明确这笔交易参照的规则 1-9字节 输入数量 被包含的输入的数量 不定 输入 一个或多个交易输入 1-9字节 输出数量 被包含的输出的数量 不定 输出 一个或多个交易输出 4字节 时钟时间 一个UNIX时间戳或区块号
- 序列化的交易长度
- 版本(4字节) + 时间戳(4字节) + 交易输入Number(var_int) + 交易输出Number(var_int) + 每个交易的输入序列化字节数(var_int) + 每个交易的输出序列化字节数(var_int)
- 每个交易的输入序列化字节数 = 引用的UTXO哈希(32字节) + 引用的输出索引序列号(4字节) + 未使用的序列号(4字节) + 脚本长度序列化Number(var_int) + 脚本长度字节数
- 每个交易的输入序列化字节数 = 交易的比特币总量(8字节) + 脚本长度序列化Number(var_int) + 脚本长度字节数
- 时间戳:
- 锁定时间(或时间戳)定义了能被加到区块链里的最早的交易时间。
- 交易中,被设置为0, 表示立即执行;
- 大于0 小于 5亿, 表示该交易所位于区块在链中的高度,意思为: 在这个指定的区块高度之前,该交易没有被包含在区块链中。
- 大于 5 亿, 表示Unix纪元时间戳,表示在这个指定时间点之前, 该交易没有被包含在区块链中。 同时意思为:该交易只有到达指定时间, 才可以被新区快打包,进行交易验证,相当于交易延后执行。
- 表格
尺寸 字段 说明 32个字节 交易 指向交易包含的被花费的UTXO的哈希指针 4个字节 输出索引 被花费的UTXO的索引号,第一个是0 1–9个字节 (可变整数) 解锁脚本尺寸,用字节表示的后面的解锁脚本长度 变长 解锁脚本 一个达到UTXO锁定脚本中的条件的脚本 4个字节 序列号 目前未被使用的交易替换功能,设成0xFFFFFFFF
- 序列号: 8d3117d26d
- 用来覆盖在交易锁定时间之前失效的交易,一项目前没有在比特币中用到的功能。
- 大多数交易把这个值设置成最大的整数(0xFFFFFFFF),并且被比特币网络忽略。
- 如果一次交易有非零的锁定时间(时间戳),那么它至少需要有一个序列号比0xFFFFFFFF低的输入来激活锁定时间。
- 交易输出结构
尺寸 字段 说明 8个字节 总量 用聪表示的比特币值(10-8比特币) 1–9个字节 (可变整数) 锁定脚本尺寸 用字节表示的后面的锁定脚本长度 变长 锁定脚本 一个定义了支付输出所需条件的脚本
一个完整的交易数据: 结构划分(该交易为真实的线上交易)
/*
01000000 //交易版本号 4字节
01 //交易输入数量 1字节
33a525c7bb912fea5e4f7633
35ac2afd236bd43c906b5559
f80c0a30c4ccb4b4 //指向的UTXO 哈希 32字节
01000000 //UTXO 序号 4 字节
6a //脚本字节数 1字节
4730440220129bfbd49e9fb990cbc542c95cbfe1
f073c5c8d34aae70d2e80b1bc6c3e3aa2202204b //包含:签名和公钥
c87a25ce402c7469a2c221cfcb26a95ea95a6142
a733e1ef9e1c242bf5c2d3012103fbf4e8da6848
51fdafdf539deffc424d995b207a8f2bc827c679
366cfcf3489f //脚本内容 106字节
ffffffff //sequence 1字节
01 //交易输出数量 1字节
b851950000000000 //输出金额 8字节
17 //锁定脚本长度 1字节
a91432f08210748b1b0b00e89953b7db2145c8f0
9d0f87 //锁定脚本 23字节
00000000 //该交易的时间戳
*/
- 区块的结构
大小 字段 描述 4字节 区块大小 用字节表示的该字段之后的区块大小 80字节 区块头 组成区块头的几个字段 1-9 (可变整数) 交易计数器 交易的数量 可变的 交易 记录在区块里的交易信息
- 1 详细解释:
- 增加了错误校验码来检查数据在转录中出现的错误。
- 校验码长4个字节,添加到需要编码的数据之后。校验码是从需要编码的数据的哈希值中得到的,所以可以用来检测并避免转录和输入中产生的错误。
- 2 为了使用Base58Check编码格式对数据进行编码:
- 1 首先进行前缀添加
- 首先我们要对数据添加一个称作“版本字节”的前缀,这个前缀用来明确需要编码的数据的类型。
- 例如:对比特币地址编码时,比特币地址的前缀是0(十六进制是0x00)
- 而对私钥编码时前缀是128(十六进制是0x80)
- 脚本地址的前缀是 0x05
- 2 计算校验码
- 采用双哈希,对之前的结果(前缀和数据)运行两次SHA256哈希算法。
checksum = SHA256(SHA256(prefix+data))
- 取上步计算哈希结果的前4个字节作为校验码。
- 校验码会添加到数据之后。
- 3 结果的组成:
- 三部分组成:前缀、数据和校验码。
比特币的地址生成:
- 生成方式: 由公钥 –》 sha256(公钥) –》 RIPEMD160(上步结果) –》base58check(上步结果) === 比特币地址;
- 示例: 1J7mdg5rbQyUHENYdx39WVWK7fsLpEoXZy; 长度为34个字节, 该为Base58check编码后的字符串。
比特币网络
- 节点采用TCP协议、使用8333端口.
校验交易
- 打包交易前,校验如何打包交易最合算。
打包交易Mempool:
- 打包交易前的校验算法, 主要数据来源.
比特币交易的集中方式:
- P2PKH: 此类交易都含有一个锁定脚本,该脚本由公钥哈希实现阻止输出功能.支付给公钥哈希的交易
- 由P2PKH脚本锁定的输出可以通过键入公钥和由相应私钥创设的数字签名得以解锁。
- P2PK: 支付给公钥的交易
- 主要目的一方面为使比特币地址更简短,另一方面也使之更方便使用。
- 多重签名交易:
- 支付给多个
- P2SH: 复杂的锁定脚本被电子指纹所取代,电子指纹为密码学哈希。
- 1 在现金交易中的锁定脚本是这种: 确保在赎回交易中提供的脚本的哈希,是这个创建地址的脚本的哈希。
mempool中的交易:
- 1 通过检查后的合法交易
- 2 检查的内容: 交易对象合法, 脚本是否合法, 是否放入区块,
- 3 交易本身的验证, 交易链的验证—》 全在已经确认的block里面,
- 4 交易与block的交互:
- 交易扔给一个交易哈希, block返回一个交易的内容
- 5 检测交易的两种路径: 检查已确认的区块, 检查mempool。
- 6 优化方案:
交易数据长度问题:
- 1 交易数据长度分为4个等级:
- 1 交易数据长度 < 253 byte; 使用1个字节表示交易长度。该字节直接表示接下来交易的数据长度,它后面紧跟交易数据;(即:在标识交易长度方面,使用了1个字节,该字节直接表示交易的长度)
- 2 交易数据长度 < 65535 byte; 使用一个字节 0xfd 作为标识,接下来的两个字节为交易数据的长度,再接下来为交易数据;(即:在标识交易长度方面:使用了3个字节,1个为标识,2个为实际数据)
- 3 交易数据长度 <= 4294967295 byte; 使用一个字节 0xfe 作为标识,接下来的四个字节为交易数据的长度,再接下来为交易数据;(即:在标识交易长度方面:使用了5个字节,1个为标识,4个为实际数据)
- 4 交易数据长度 > 4294967295 byte; 使用使用一个字节 0xfe 作为标识,接下来的八个字节为交易数据的长度,再接下来为交易数据;(即:在标识交易长度方面:使用了9个字节,1个为标识,8个为实际数据)
创币交易(coinbase 交易):
- 与常规交易不同,创币交易没有输入,不消耗UTXO。它只包含一个被称作coinbase的输入,仅仅用来创建新的比特币。创币交易有一个输出,支付到这个矿工的比特币地址。
脚本数据长度:
- 脚本数据长度分为 5 个等级:
- 1 dataLenth = 0, OpCode = OP_0
- 2 dataLenth = 1, OpCode = OP_1 – OP_16, data= 1–16
- dataLenth = 1, OpCode = OP_1NEGATE
- 3 dataLenth <= 75, OpCode = dataLenth
- 4 dataLenth <= 255, OpCode = OP_PUSHDATA1
- 5 dataLenth <= 65535, OpCode = OP_PUSHDATA2
脚本操作码
签名的限制:
公钥格式:
闪电网络
- 闪电网络的关键技术有三,后后依赖于前前,依次是:RSMC(序列到期可撤销合约),HTLC(哈希时间锁定合约)和闪电网络。
- RSMC
- 1 闪电网络的基础是交易双方之间的双向微支付通道,RSMC定义了该双向微支付通道的最基本工作方式。
- 2 微支付通道中沉淀了一部分资金,通道也记录有双方对资金的分配方案。通道的设立会记录在比特币区块链上。
- 3 为了鼓励双方尽可能久地利用通道进行交易,RSMC对主动终止通道方给予了一定的惩罚:主动提出方其资金到账将比对方晚,因此谁发起谁吃亏。
- 4 通道余额分配方案的本质是结算准备金。在此安排下,因为要完全控制资金交收风险,每笔交易都不能突破当前结算准备金所施限制。
Txmessage 验证
进入mempool的交易:
脚本包含的内容:
特殊的交易输出,导致的特殊结果
签名类型:
交易输入签名的生成:
signrawtransaction \
[{"txid":txid,"vout":n,"scriptPubKey":hex,"redeemScript":hex},...] [,...] \
[sighashtype="ALL"]
bitcoind createrawtransaction \
'[{"txid":"296ea7bf981b44999d689853d17fe0ceb852a8a34e68fcd19f0a41e589132156","vout":0}]' \
'{"1Q8s4qDRbCbFypG5AFNR9tFC57PStkPX1x":0.1, "1Lab618UuWjLmVA1Q64tHZXcLoc4397ZX3":0.0989}'
{
"txid" : "54f773a3fdf7cb3292fc76b46c97e536348b3a0715886dbfd2f60e115fb3a8f0",
"version" : 1,
"locktime" : 0,
"vin" : [
{
"txid" : "296ea7bf981b44999d689853d17fe0ceb852a8a34e68fcd19f0a41e589132156",
"vout" : 0,
"scriptSig" : {
"asm" : "",
"hex" : ""
},
"sequence" : 4294967295
}
],
"vout" : [
{
"value" : 0.10000000,
"n" : 0,
"scriptPubKey" : {
"asm" : "OP_DUP OP_HASH160 fdc7990956642433ea75cabdcc0a9447c5d2b4ee OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a914fdc7990956642433ea75cabdcc0a9447c5d2b4ee88ac",
"reqSigs" : 1,
"type" : "pubkeyhash",
"addresses" : [
"1Q8s4qDRbCbFypG5AFNR9tFC57PStkPX1x"
]
}
},
{
"value" : 0.09890000,
"n" : 1,
"scriptPubKey" : {
"asm" : "OP_DUP OP_HASH160 d6c492056f3f99692b56967a42b8ad44ce76b67a OP_EQUALVERIFY OP_CHECKSIG",
"hex" : "76a914d6c492056f3f99692b56967a42b8ad44ce76b67a88ac",
"reqSigs" : 1,
"type" : "pubkeyhash",
"addresses" : [
"1Lab618UuWjLmVA1Q64tHZXcLoc4397ZX3"
]
}
}
]
}
case :
hashType & 0x1f:
case : 0x10 == 2 (SIGHASH_NONE)
case : 0x11 == 3 (SIGHASH_SINGLE)
case : 0x01 == 1 (SIGHASH_ALL)
//一个完整的交易
type Tx struct {
Hash utils.Hash //本交易的哈希
LockTime uint32 //交易时间戳
Version int32 //版本号
Ins []*TxIn //交易输入
Outs []*TxOut //交易输出
}
//交易输入
type TxIn struct {
PreviousOutPoint *OutPoint //引用的UTXO
ScriptSig []byte //签名脚本
Sequence uint32 //todo ?
}
//指向输入中引用的UTXO
type OutPoint struct {
Hash *utils.Hash //该 UTXO 交易的哈希
Index uint32 //该 UTXO的索引号
}
//交易输出
type TxOut struct {
Value int64 //交易币值
OutScript []byte //锁定脚本
}
// digest represents the partial evaluation of a checksum.
// 摘要表示对校验和的部分求值
type digest struct {
h [8]uint32
x [chunk]byte
nx int
len uint64
is224 bool // mark if this digest is SHA-224
}
//解析后的脚本结构
type ParsedOpCode struct {
opValue byte //操作码
length int //四种情况, 1:data为nil; -1:数据长度用一个字节标识;-2:数据长度用两个字节标识;-4:数据长度用四个字节标识
data []byte //脚本数据
}
3Bzt3JA9eebS2FcgGpSSQDETmewhJUWjFs
//
type ScriptFreeList chan []byte
var scriptPool ScriptFreeList = make(chan []byte, FreeListMaxItems)