交易
{
"version": 1,
"locktime": 0,
"vin": [
{
"txid":"7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
"vout": 0,
"scriptSig": "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
"sequence": 4294967295
}
],
"vout": [
{
"value": 0.01500000,
"scriptPubKey": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG"
},
{
"value": 0.08450000,
"scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
}
]
}
// - 7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18交易的vout
"vout": [
{
"value": 0.10000000,
"scriptPubKey": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG"
}
]
-
交易截圖(代碼中的正在進行的交易)
iShot2022-04-06 18.04.52.png -
交易截圖(代碼中的 7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18指定的交易)
iShot2022-04-06 18.05.26.png
上邊的input中的address 表示的是input中的交易中付款方的地址, output中的address 表示的是output中的交易中收款方的地址
-
交易的輸入輸出
- UTXO(unspent transaction outputs, 未花費的交易輸出) : 所有UTXO的集合被稱為UTXO集钢颂,目前有數(shù)百萬個UTXO甘改。 當(dāng)新的UTXO被創(chuàng)建主胧,UTXO集就會變大煞烫,當(dāng)UTXO被消耗時,UTXO集會隨著縮小国撵。每一個交易都代表UTXO集的變化(狀態(tài)轉(zhuǎn)換)
- 用戶收到比特幣是指的錢包檢測到可用的UTXO, 通過錢包所控制的密鑰我們可以花費這些UTXO, 所以余額指的是所有UTXO的總和(可能分布在數(shù)百個交易和區(qū)塊中).
- 一個用戶的比特幣余額: 比特幣錢包掃描區(qū)塊鏈并聚集所有屬于該用戶的UTXO來計算用戶的余額, 大多數(shù)錢包維護一個數(shù)據(jù)庫或使用數(shù)據(jù)庫服務(wù)來存儲所有UTXO的快速參考集妈嘹,這些UTXO由用戶所有的密鑰來控制花費行為。
- 一個UTXO只能在一次交易中作為一個整體被消耗凡恍。這樣的話,由于UTXO(或交易輸出)的不可分割特性怔球,大部分比特幣交易都會產(chǎn)生找零.
- 每一筆交易都會消耗之前被記錄的UTXO, 并創(chuàng)建新的UTXO以備未來的交易的消耗, 比特幣的交易就是在交易鏈中消耗和創(chuàng)建UTXO, 一筆比特幣的交易通過使用所有者的簽名來解鎖UTXO, 通過使用新的所有者的比特幣地址來鎖定并創(chuàng)建UTXO;
-
交易輸出
- 每一筆比特幣交易都會創(chuàng)建輸出,并被比特幣賬簿記錄下來(OP_RETURN除外), 幾乎所有的輸出都能創(chuàng)造一定數(shù)量的可用于支付的比特幣.
- 交易的輸出包含
- 一定數(shù)量的比特幣(value)
- 確定花費這些輸出所需的條件(scriptPubKey)
- 序列化和反序列化
- 序列化
- 將對象類型轉(zhuǎn)換成字節(jié)流的過程
- 反序列化
- 將字節(jié)流轉(zhuǎn)換成對象類型的過程
- 序列化
-
交易輸入
- 將UTXO標(biāo)記為被消費并通過解鎖腳本提供所有權(quán)證明.
- 當(dāng)構(gòu)建一個交易的時候, 錢包通過控制地址對應(yīng)的UTXO中選擇足夠的價值來執(zhí)行被請求的付款(有時一個UTXO就足夠, 有時需要很多個), 對于將用于進行此次付款的每個UTXO, 錢包都會創(chuàng)建一個指向UTXO的輸入, 并使用解鎖腳本解鎖它.
- 交易的輸出包含
- UTXO指針: 一個交易ID嚼酝,引用包含正在使用的UTXO的交易(通過指向UTXO被記錄在區(qū)塊鏈中所在的交易的哈希值和序列號來實現(xiàn))
- 索引: 用于標(biāo)識來自該交易vout的索引(從0開始)
- 解鎖腳本: 用于解鎖支出
- 序列號:
- 序列化和反序列化
- 序列化
- 將對象類型轉(zhuǎn)換成字節(jié)流的過程
- 反序列化
- 將字節(jié)流轉(zhuǎn)換成對象類型的過程
- 序列化
- 交易費
- 大多數(shù)交易包含交易費(礦工費). 礦工會根據(jù)不同的標(biāo)準(zhǔn)(包括交易費)對交易進行優(yōu)先級排序, 交易費會影響處理優(yōu)先級. 交易費不足或者沒有交易費的交易可能會被推遲甚至可能會不被處理. 盡管交易費不是強制的, 而且沒有交易費最終也有可能會被處理, 但是交易費將提高處理的優(yōu)先級.
- 現(xiàn)在任何創(chuàng)建交易的比特幣服務(wù)都必須動態(tài)實現(xiàn)收費, 動態(tài)費用通過費用估算服務(wù)/費用估算算法實現(xiàn). 費用化估算包括簡單的(計算最后一個塊中礦工費的平均值的中位數(shù)) / 復(fù)雜的(統(tǒng)計分析), 估計必要費用(以字節(jié)為單位), 是交易具有很高的可能性被選擇并打包進一定數(shù)量的塊內(nèi).
- 交易的數(shù)據(jù)結(jié)構(gòu)沒有交易費的字段。相替代地竟坛,交易費是指輸入和輸出之間的差值闽巩。從所有輸入中扣掉所有輸出之后的多余的量會被礦工作為礦工費收集走(交易費即輸入總和減輸出總和的余量:交易費 = 求和(所有輸入) - 求和(所有輸出);
-
比特幣交易腳本
- 鎖定腳本
- 一個放置在輸出上面的花費條件:它指定了今后花費這筆輸出必須要滿足的條件。
- 解鎖腳本
- 一個滿足鎖定腳本設(shè)定的花費條件的腳本, 通過解鎖腳本可以允許一個vout被消費, 解鎖腳本是每一筆比特幣交易輸入的一部分, 往往含有一個用戶的比特幣錢包(用戶的私鑰)生成的數(shù)字簽名, 由于解鎖腳本通常包含一個數(shù)字簽名, 所以也被稱為ScriptSig.
- 流程
- 每個比特幣節(jié)點都會通過同時執(zhí)行鎖定和解鎖腳本來驗證一筆交易, 每個輸入都包含一個解鎖腳本, 并引用之前的UTXO, 驗證軟件將復(fù)制解鎖腳本, 檢索輸入所引用的UTXO, 并復(fù)制鎖定腳本, 然后依次執(zhí)行鎖定腳本和解鎖腳本, 如果解鎖腳本滿足鎖定腳本條件, 則輸入有效.
- P2PK(Pay-to-Public-Key)付款至公鑰
- 腳本
- 鎖定腳本
PUSHDATA(PubKey)
CHECKSIG - 解鎖腳本
PUSHDATA(Sig)
- 鎖定腳本
- 拼接
PUSHDATA(Sig)
PUSHDATA(PubKey)
CHECKSIG
- 腳本
- P2PKH(Pay-to-Public-Key-Hash)付款至公鑰hash
- A->B : scriptPubKey: OP_DUP OP_HASH160 <B pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG B->C :scriptSig: <B 私鑰對交易的簽名> <B 公鑰>
- 將輸入鎖定為一個公鑰哈希值担汤,即我們常說的比特幣地址.
- 腳本
- 鎖定腳本
OP_DUP
OP_HASH160
PUSHDATA(PubKey)
OP_EQUALVERIFY
OP_CHECKSIG - 解鎖腳本
PUSHDATA(Sig)
PUSHDATA(PubKey)
- 鎖定腳本
- 拼接
PUSHDATA(Sig)
PUSHDATA(PubKey)
OP_DUP
OP_HASH160
PUSHDATA(PubKey)
OP_EQUALVERIFY
OP_CHECKSIG - 上述交易的腳本執(zhí)行流程(先執(zhí)行解鎖腳本,在執(zhí)行鎖定腳本, 因為是個棧結(jié)構(gòu),所以會先鎖定然后再解鎖).
-
上述的<Cafe Public Key>地址是長度為520位(65字節(jié))的全公鑰(04前綴 || x坐標(biāo) || y坐標(biāo));
iShot2022-04-06 18.18.28.png
- 多重簽名
- 其中N個公鑰被記錄在腳本中涎跨,并且至少有M個必須提供簽名來解鎖資金
- 鎖定腳本
M <Public Key 1> <Public Key 2> ... <Public Key N> N CHECKMULTISIG - 解鎖腳本, 解鎖腳本中有個0的原因是因為 CHECKMULTISIG的執(zhí)行中有一個bug, CHECKMULTISIG彈出最上面的項目,這是N(在這個例子中N是“3”)崭歧。然后它彈出N個項目隅很,這是可以簽名的公鑰。在這個例子中率碾,公鑰A叔营,B和C.然后,它彈出一個項目播掷,即M审编,仲裁(需要多少個簽名)。這里M = 2歧匈。此時垒酬,CHECKMULTISIG應(yīng)彈出最終的M個項目,這些是簽名件炉,并查看它們是否有效勘究。然而,不幸的是斟冕,實施中的錯誤導(dǎo)致CHECKMULTISIG再彈出一個項目(總共M + 1個)口糕。檢查簽名時,不考慮額外的項目磕蛇,因此它對CHECKMULTISIG本身沒有直接影響景描。但是,必須存在額外的值秀撇,因為如果不存在超棺,則當(dāng)CHECKMULTISIG嘗試彈出空堆棧時,會導(dǎo)致堆棧錯誤和腳本失敽茄唷(將交易標(biāo)記為無效)棠绘。因為額外的項目被忽略,它可以是任何東西,但通常使用0氧苍。所以正確的解鎖腳本中前邊多了個0;
0 <Signature B> <Signature C> - 拼接
0
<Signature B>
<Signature C>
2
<Public Key A>
<Public Key B>
<Public Key C>
3
CHECKMULTISIG
- P2SH(Pay-to-Script-Hash)付款至腳本hash
scriptPubKey: OP_HASH 6fe28c0ab6f1b372c1a6 OP_EQUAL 這個腳本, hash(x) = 6fe28c0ab6f1b372c1a6 我們只是提供?一個x滿?足這個條件夜矗,就可以證明我可以花費這筆錢了了。scriptPubKey: OP_HASH 6fe28c0ab6f1b372c1a6 OPEQUAL 這?6fe28c0ab6f1b372c1a6不不是簡單的?一個數(shù)字的hash让虐,?而是?一段script的hash(簡稱redeemScript)紊撕。 OP_HASH hash(redeemScript) OPEQUAL 我們可以理理解成只要你提供了了?段script,它的二進制hash和目標(biāo)匹配澄干,那么你就可以花費這筆錢了.
-
解決多重簽名中使用不方便的問題(花費這筆UTXO時: 在客戶付款前將該腳本發(fā)送給每一位客戶逛揩,而每一位顧客也必須使用特制的能產(chǎn)生客戶交易腳本的比特幣錢包軟件,每位顧客還得學(xué)會如何利用腳本來完成交易麸俘。).
image.png 可以看到贖回腳本不是在鎖定腳本中顯示, 并且贖回腳本值是展示在解鎖腳本中,也就是復(fù)雜的計算工作從(企業(yè)收款的那筆交易中的)發(fā)送方轉(zhuǎn)移到收款方. 同時礦工的交易費用從發(fā)送方轉(zhuǎn)移到收款方.
當(dāng)有人試圖花費這筆UTXO時,附上原始贖回腳本(與UTXO鎖定的哈希)和必要的解鎖簽名即可, 即:
-
redeemScript
非多重支付類型
PUSHDATA(PubKey)
CHECKSIG多重支付類型
2
PUSHDATA(PubKey_1)
PUSHDATA(PubKey_2)
PUSHDATA(PubKey_3)
3
CHECKMULTISIG
-
解鎖腳本就是:
非多重支付類型
PUSHDATA(Sig)
PUSHDATA(序列化的redeemScript)多重支付類型
0
PUSHDATA(Sig_1)
PUSHDATA(Sig_2)
PUSHDATA(序列化的redeemScript)
鎖定腳本變成:
HASH160
PUSHDATA(redeemScriptHash)
EQUAL-
驗證
-
驗證序列化的redeemScript是否與output script中的hash值是否匹配
非多重支付
PUSHDATA(Sig)
PUSHDATA(序列化的redeemScript)
HASH160
PUSHDATA(redeemScriptHash)
EQUAL多重支付
0
PUSHDATA(Sig_1)
PUSHDATA(Sig_2)
PUSHDATA(序列化的redeemScript)
HASH160
PUSHDATA(redeemScriptHash)
EQUAL
-
反序列化執(zhí)行redeemScript, 驗證input script中給出的簽名是否正確
- 非多重支付
PUSHDATA(Sig) // - 這行是執(zhí)行完第一步驗證后棧中剩余的
PUSHDATA(PubKey) // - redeemScript中的代碼
CHECKSIG // - redeemScript中的代碼 - 多重支付
0 // - 這行是執(zhí)行完第一步驗證后棧中剩余的
PUSHDATA(Sig_1) // - 這行是執(zhí)行完第一步驗證后棧中剩余的
PUSHDATA(Sig_2) // - 這行是執(zhí)行完第一步驗證后棧中剩余的
2 // - redeemScript中的代碼
PUSHDATA(PubKey_1) // - redeemScript中的代碼
PUSHDATA(PubKey_2) // - redeemScript中的代碼
PUSHDATA(PubKey_3) // - redeemScript中的代碼
3 // - redeemScript中的代碼
CHECKMULTISIG // - redeemScript中的代碼
- 非多重支付
-
同時可以將腳本哈希編譯為一個地址, 即P2SH地址是基于Base58編碼的一 個含有20個字節(jié)哈希的腳本(像比特幣地址是基于Base58編碼的一個含有20個字節(jié)的公鑰辩稽。由于P2SH地址采用5作為前綴,這導(dǎo)致基于Base58編碼的地址以“3”開頭);
- 鎖定腳本
-
數(shù)字簽名
- 比特幣中使用的數(shù)字簽名算法是ECDSA(Elliptic Curve Digital Signature Algorithm, 橢圓曲線數(shù)字簽名算法), 用于基于橢圓曲線私鑰/公鑰數(shù)字簽名的算法, 該簽名算法用于 OP_CHECKSIG从媚,OP_CHECKSIGVERIFY逞泄,OP_CHECKMULTISIG和OP_CHECKMULTISIGVERIFY, 當(dāng)鎖定腳本看到這些操作時候, 解鎖腳本必須包含一個 ECDSA簽名.
- 用途
- 資金所有者已經(jīng)授權(quán)了支出這些資金.
- 授權(quán)不可否認(rèn).
- 交易在簽名之后沒有任何人篡改.
- 創(chuàng)建數(shù)字簽名
-
((Sig = F{sig}(F{hash}(m), dA))) : 使用私鑰對交易的hash做簽名運算,得到簽名結(jié)果
- dA 是簽名私鑰
- m : 交易
- F{hash} : hash 函數(shù)
4.F{sig} : 簽名算法; - Sig: 結(jié)果簽名
-
Sig是有兩個值組成的 即:Sig = (R, S), 得到R和S之后序列化為字節(jié)流,使用一種稱為DER(Distinguished Encoding Rules, 分辨編碼規(guī)則)的國際標(biāo)準(zhǔn)編碼方案.
例如 : 3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301
- 0x30表示DER序列的開始
- 0x45 - 序列的長度(69字節(jié))
- 0x02 - 接下來是一個整數(shù)
- 0x21 - 整數(shù)的長度(33字節(jié))
- R-00884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb
- 0x02 - 接下來是一個整數(shù)
- 0x20 - 整數(shù)的長度(32字節(jié))
- S-4b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813
- 后綴(0x01)指示使用的哈希的類型(SIGHASH_ALL)
-
-
驗證簽名
- 要驗證簽名, 必須有簽名(R和S), 序列化交易和公鑰.
-
簽名可以指示交易數(shù)據(jù)的哪一部分包含在私鑰簽名的hash中(使用后綴表示), input中的不同的交易可以使用不同后綴類型,使每個交易擁有自己的后綴類型.
image.png
image.png
-
ECDSA算法
-
簽名
image.png
- k是臨時私鑰, K = k*G, 得到公鑰K, 其中Kx記作點的x坐標(biāo), Ky 記作點的y坐標(biāo).
- R = Kx
- dA是簽名私鑰
- m是交易數(shù)據(jù), Hash(m)是對交易做hash運算.
- p是橢圓曲線的素數(shù)階, 在 secp256k1 曲線中, p = 2^256 – 2^32 – 2^9 – 2^8 – 2^7 – 2^6 – 2^4 – 1
- 計算的到S, 如果, s==0, 重新執(zhí)行第一步. 從而得到 R和S;
-
驗證簽名
image.png- R和S是簽名值
- Qa是公鑰
- m是簽署的交易數(shù)據(jù)
- G是橢圓曲線發(fā)生器點
當(dāng)且僅當(dāng) 計算的點Px == R, 驗證簽名通過
-