比特幣協議中最重要的部分就是交易,比特幣協議其他的部分也都是為了確保交易的生成、廣播、驗證和打包而實現的。
本文內容主要是針對交易的資料結構以及對原始交易進行解析,後期還會繼續寫交易的生命週期
、交易指令碼
等文章。
原始交易
比特幣的交易是以位元組的形式存在塊中的,使用bitcoin-cli
命令可以獲得一個原始的交易資料。例如:
bitcoin-cli getrawtransaction 2eb0e06af852f049f7dc641f740ded17a11cde138fd3d3d3c4a078649c053260
會得到一個完整的原始交易資料:
010000000112255d3c...88ac00000000複製程式碼
^rawtransaction
得到的原始交易是經過hex
處理的,並沒有顯示為原始位元組。從上面的hex
字串也並不能看到有用的資訊(如果想檢視json格式的交易可以檢視api).
原始的交易資料並不能直觀地體現交易的具體內容,如何才能得到具體的交易內容呢?藉助這個例子可以詳細的分析下交易結構和原始資料解析。先看下交易的資料結構。
交易的資料結構
一個完整的交易由以下的元素構成的:
- 版本 version
- 輸入 tx_in
- 輸出 tx_out
- 鎖定時間 lock_time
其中交易的輸入和輸出有可能是一個或多個,上面所說的交易就有一個輸入和兩個輸出。
版本(version)是明確一筆交易參照的規則,除非有重大升級的情況下,版本號基本無變化,是比較固定的一個值。
交易的鎖定時間是被該交易被加到區塊的最早時間,在大多數的情況下他的值都是0,表示需要立即被加入區塊中。如果鎖定時間大於0而小於5億,它的值就表示區塊高度。如果大於5億就表示一個Unix時間戳。
上面所描述的交易構成又是如何在原始交易裡面體現的呢?這就需要對原始交易進行拆解,看下交易結構如何在原始交易中定義的:
描述 | 長度 | 原始欄位 |
---|---|---|
版本 | 4 | 01000000 |
交易輸入的個數 | 1+ | 01 |
交易輸入 | 41+ | 12255......ffffffff ^ins |
輸出的個數 | 1+ | 02 |
交易輸出 | 9+ | 00e1f...988ac^outs |
鎖定時間 | 4 | 00000000 |
通過上面的表格可以看到一個原始交易是如何儲存交易的。原始交易中除了包括交易所需要的資料之外,因為交易的輸入和輸出有可能會出現多個,所以原始交易還需要額外的欄位用來描述交易的輸入、輸出個數,輸入、輸出的個數並不是固定的,因此用來描述個數使用的是變長整數(VarInt),他的目的是在節省空間的情況下能夠儲存足夠使用的整數。
這裡描述了一個交易的資料結構以及他在原始交易中如何儲存的,但是並沒有拆解出具體的輸入
、輸出
內容。下面就對輸入
、輸出
進行詳細的拆解,先從輸入開始。
交易輸入
一個交易的輸入是由下面的元素組成:
- 引用交易的hash
- 引用交易的索引
- 解鎖指令碼
那麼交易輸入又是如何在原始交易裡面進行儲存的呢?從上面的分析我們可以知道該例子交易中只有一個交易的輸入。下面就是從原始交易中解析下交易的輸入
:
描述 | 長度 | 原始欄位 |
---|---|---|
前置交易hash | 32 | 12255...ae^previous_hash |
前置交易的索引 | 4 | 01000000 |
解鎖指令碼長度 | 1+ | 8a |
解鎖指令碼 | ? | 4730...eae^in_script |
序列 | 4 | ffffffff |
這裡獲取到的hash和網站上面顯示的hash並一致,這是因為位元組序的儲存和讀取的方式不一致造成的,即大端和小端模式:
網路協議規定接收到第一個位元組是高位元組,存放在低地址,所以傳送時會首先去低地址取資料的高位元組
而在比特幣的儲存中hash是做為一個整數儲存的,因此在取hash時候需要從低地址開始獲取。
而解鎖指令碼的長度也是未知的,就需要使用一個可變整形用來表示解鎖指令碼的長度。對於交易指令碼
的拆解會在以後的文章中進行。
通過上面表格的描述就可以從一個交易中拆解出它的輸入了,下面繼續對交易輸出進行拆解。
交易輸出
一個交易的輸出是由下面的元素組成的:
- 輸出金額
- 輸出指令碼
那交易的輸出在原始交易中又是如何儲存的呢?從上面的交易拆解中可以知道該例子交易是有兩個輸出,這裡只需要針對第一個輸出進行拆解即可:
描述 | 長度 | 原始欄位 |
---|---|---|
value 單位是1聰 | 8 | 00e1f50500000000 |
鎖定指令碼長度 | 1+ | 19 |
鎖定指令碼 | ? | 76a9147072795a259b38bf476e053852ab85221ba9467b88ac |
注意輸出的金額也涉及到大端傳輸的問題,解析的時候需要從低地址開始讀取。
這裡並沒有對鎖定指令碼
進行拆解,所以還看不到輸出的地址,對於一個比特幣交易來說,交易本身是不用關心輸出的地址,交易只需要關心鎖定指令碼,當使用的時候能使用使用正確的解鎖指令碼即可動用比特幣。關於交易指令碼
會在以後的內容裡詳細的介紹。
交易本身的資料結構並不沒有交易費
的概念,每筆交易的手續費是使用總輸入-總輸出
計算得到的,所以在交易的資料結構中沒有體現。
總結,一個原始的交易包含了一個交易所需要的所有資料,他們按照比特幣協議規定的規則進行儲存。在交易生成,驗證的時候也需要按照xiang'tong