交易 - 比特幣開發(fā)指南

交易 - 比特幣開發(fā)指南

原文鏈接: https://bitcoin.org/en/developer-guide#transactions

翻譯: terryc007

版本:1.0


比特幣開發(fā)指南

1. 區(qū)塊鏈

2. 交易

3.合約

4.錢包

5.支付處理

6.工作模式

7.P2P網(wǎng)絡

8.挖礦


交易讓用戶花掉satoshis。每個交易由好幾個部分組成,這些組成部分可以允許簡單直接的支付,也可以實現(xiàn)復雜的交易。 本節(jié)將講述每個部分,同時展示如何運用他們來創(chuàng)建復雜的交易。

為簡化,本節(jié)不考慮coinbase交易。 Coinbase交易僅能由礦工創(chuàng)建,同時,對于下面的很多規(guī)則,并不適用Coinbase交易。如想了解Coinbase交易,請你閱讀在區(qū)塊鏈章節(jié)中有關coinbase交易部分的內(nèi)容。

上圖展示了比特幣交易的主要構(gòu)成部分。每個交易至少包含一個輸入,一個輸出。每個輸入會花掉satoshis去支付之前的輸出,然后每個輸出會以一個未被花掉的交易輸出(UTXO)形式存在,直到后續(xù)的輸入把它花掉。 當比特幣錢包說你有10000個satoshis余額時,它其實是你一個10000個sotoshi以一個或多個UTXO的形式存在。

每個交易以4字節(jié)的版本號開頭,交易版本號用來告訴比特幣節(jié)點,礦工該用那些規(guī)則來驗證它。這讓比特幣開發(fā)者,在不違反之前交易規(guī)則前提下,為未來的交易新增規(guī)則。

每輸出基于他在交易中的位置,有一個隱式的索引號 - 第一個輸出的索引號是0. 每個輸出有一定數(shù)量的satoshi,以用于支付一個條件公鑰腳本。只要滿足公鑰腳本條件,任何人都可以花掉里面的satoshi。

每個輸入使用一個交易di(txid),輸出索引號(通常叫做:作為輸出向量的vout )來識別一個被發(fā)掉的特定的輸出。同時,每個輸入還包含了一個簽名腳本。該簽名腳本允許輸入為公鑰腳本條件,提供數(shù)據(jù)參數(shù)。 (序列號,鎖定時間相關內(nèi)容會在后面的小節(jié)再講解。)

下面的圖通過展示Alice發(fā)送一個交易給Bob,讓后Bob花費這個交易輸出的流程,闡明如何使用這些功能。 Alice跟Bob都使用最為通用的支付公鑰哈希 Pay-to-Public-Key-Hash(P2PKH)的交易類型。P2PKH可以讓Alice給一個通用的比特幣地址支付satoshi,讓后讓Bob以后可以使用一個簡單的密鑰花掉這些satoshi。

在Alice跟Bob間能創(chuàng)建第一筆交易前,Bob必須創(chuàng)建一個私鑰/公鑰密鑰對。比特幣采用通過secp256k1曲線實現(xiàn)的橢圓曲線數(shù)字簽名算法(the Elliptic Curve Digital Signature Algorithm ECDSA). secp256k1密鑰是一個256位的隨機數(shù)據(jù)。該密鑰的拷貝可變換成一個確定的secp256k1公鑰。因為這個變換能夠可靠的重復,即只要私鑰不變,通過這個變換就能生成同樣的公鑰,所以在以保存了私鑰的情況下,就沒有必要存儲公鑰了。

然后公鑰被加密哈希。這個加密哈希后的哈希值,也是可以被可靠的生成出來,因此也沒有必要保存它。短化的,模糊處理了的公鑰,不僅使得手動交易更簡單,同時為預防一些意外情況(后續(xù)會講到的:允許通過公鑰數(shù)據(jù)來重建私鑰)提供了安全保障。

Bob給Alice提供一個公鑰哈希值。 公鑰哈希值通常以比特幣地址的形式進行編碼,再發(fā)送出去。 比特幣地址是一串通過base58編碼后的字符串,包含一個地址版本號,哈希值,錯誤檢查校驗和。這個地址可以通過任何媒介進行傳輸,包括單向媒介(可以防止支付方與收款方進行通信),同時比特幣地址可進一步被編碼成另外一種格式,比如以QR碼格式(bitcoin:URI).

一但Alice獲取Bob的比特幣錢包地址,并反編碼成一個標準的哈希值,她就能創(chuàng)建與Bob間的第一個交易。她創(chuàng)建一個標準的P2PKH交易輸出。交易輸出里包含了一些指令: 這些指令允許人可以花掉這個輸出,只要他能證明他們控制了與Bob相應的哈希公鑰相對應的私鑰。這些指令被稱之為: 公鑰腳本(pubkey script)或者 scriptPubKey。

然后Alice廣播這個交易,同時交易被加入到區(qū)塊鏈。比特幣網(wǎng)絡把這個交易分類成一個未花費交易輸出UTXO,而Bob的錢包會顯示為一個可花的余額。

過后,當Bob決定要花掉這個UTXO時,他必須創(chuàng)建一個輸入,這個輸入通過交易哈希id(txid),來引用Alice的交易,以及通過輸出的序列號來使用Alice使用的輸出。Bob必須創(chuàng)建一個簽名腳本 — 其實就是一些參數(shù)數(shù)據(jù)集合,這些參數(shù)數(shù)據(jù)滿足在之前Alice交易輸出的公鑰腳本中設置的條件。簽名腳本也叫scriptSigs.

公鑰腳本和簽名腳本通過secp256k1公鑰,帶有條件邏輯的簽名組合起來,來創(chuàng)建一個可編程的授權(quán)機制。

對于P2PKH類型輸出,Bob的簽名腳本包含以下兩種數(shù)據(jù):

  1. 他的完整(沒經(jīng)過哈希的)公鑰,這樣公鑰腳本能夠檢查Alice提供的公鑰哈希是否跟完整公鑰經(jīng)過哈希處理后所得的哈希值一致。
  1. 一個secp256k1簽名, 它是通過ECDSA加密公式把一定的交易數(shù)據(jù),與Bob私鑰結(jié)合起來生成的。這可以讓公鑰腳本驗證:Bob是那個創(chuàng)建那個公鑰的密鑰的擁有者。

Bob的 secp256k1簽名不僅是證明Bob控制了他的密鑰,它也使得他的交易中非簽名腳本部分是防篡改的,因此Bob能安全地在p2p網(wǎng)絡中廣播交易。

如上圖所示,Bob簽名的數(shù)據(jù)包括交易id,前一交易的輸出索引號,之前輸出公鑰腳本,Bob創(chuàng)建的公鑰腳本(可被下一個接受者發(fā)掉這個交易的輸出),可被下一個接受者發(fā)掉的satoshi的數(shù)量。本質(zhì)上講,整個交易除了簽名腳本,secp256k1簽名外,整個交易都會被簽名。

Bob把他的簽名,以及公鑰放到簽名腳本后,他通過P2P比特幣網(wǎng)絡廣播該交易給比特幣礦工。每個比特幣節(jié)點,礦工會獨立的驗證交易后,再向其他節(jié)點廣播該交易,或嘗試添加到新區(qū)塊交易中。

P2PKH 腳本驗證

驗證程序需要對簽名腳本跟公鑰腳本求值。 在一個P2PKH輸出,公鑰腳本是這樣子的:

OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG

花費者簽名腳本被求值,并被放到腳本的開頭處。在一個P2PKH交易中,簽名腳本包含一個secp256k1簽名(sig),一個完整公鑰(publkey), 并以如下方式串起來:

<Sig> <PubKey> OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

這個腳本語言一種類Forth的基于堆棧的編程語言,專門為比特幣而設計的無狀態(tài)的,非圖靈完備的腳本語言。無狀態(tài)保證了一個交易一但被加到區(qū)塊鏈中,就沒有條件使得其永久不可用[?]。 非圖靈完備(更具體來說,就是缺少循環(huán)或goto語句)使得腳本語言擁有更少的靈活性,更多的可預測性,這極大的簡化了安全模型。

為測試交易是否有效,簽名腳本和公鑰腳本操作每次只執(zhí)行一個: 先執(zhí)行Bob的簽名腳本,接著是Alice的公鑰腳本。 下圖展示了一個標準的P2PKH公鑰腳本的計算過程。

  • 把簽名(來自Bob的簽名腳本)壓入一個空的堆棧。因為它僅僅是一個數(shù)據(jù),所以僅需要把他壓入堆棧。然后把公鑰(來自Bob的簽名腳本)壓入堆棧頂部。

  • 從Alice的公鑰腳本,執(zhí)行OP_DUP指令。OP_DUP會把棧頂?shù)臄?shù)據(jù)復制一份并壓入棧頂 — 在這,就是在在棧頂復制一份Bob的公鑰。

  • 然后再執(zhí)行OP_HASH160, 該指令會對棧頂?shù)臄?shù)據(jù)進行哈希,并把哈希值壓入堆棧 — 在這,就是創(chuàng)建Bob公鑰的哈希,并壓入棧頂。

  • 然后,Alice的腳本把第一個交易中,Bob給她的公鑰壓入棧頂。這時,在堆棧棧頂有兩份Bob的公鑰哈希值。

  • 現(xiàn)在開始有意思了:Alice的公鑰腳本會執(zhí)行OP_EQUALVERIFY. OP_EQUALVERIFY 相對于執(zhí)行了OP_EQUAL ,讓后再執(zhí)行OP_VERIFY(在上面沒有顯示).

    OP_EQUAL(在上面沒有顯示) 會檢查在棧頂兩個值;在這,它會檢查從Bob完整公鑰生成的公鑰哈希值是否等于Alice提供的哈希公鑰值(她創(chuàng)建交易1時,從Bob拿獲得的)。OP_EQUAL會彈出(即把數(shù)據(jù)從棧頂刪除)剛比較的兩個值,并把比較結(jié)果壓入堆棧:0(false)或1(true)。

    OP_VERIFY(在上面沒有顯示)會檢測棧頂?shù)闹怠H绻凳莊alse,它會立即停止計算,交易驗證失敗。否則它會把true從棧頂彈出。

  • 最終,Alice的公鑰腳本執(zhí)行OP_CHECKSIG, 它會檢查Bob提供的簽名,以及Bob提供授權(quán)的公鑰。如果簽名跟公鑰匹配,并且是通過所有需要的數(shù)據(jù)簽名生成的,OP_CHECKSIG會在棧頂壓入true。

在完成公鑰計算后,如果此時棧頂不是false,那么這個交易就是有效的(假使該交易沒有什么其他問題)。

P2SH 腳本

公鑰腳本被花費者創(chuàng)建,他們對腳本到底做了什么沒有什么太大興趣。而接受者卻很關心腳本的條件,如果他們愿意,他們能要求花費者使用特定的公鑰腳本。不幸的是,比起短比特幣地址,自定義公鑰腳本很不方便。 在廣泛實現(xiàn)BIP70支付協(xié)議(后面在討論)之前,還沒有一個標準的方式實現(xiàn)程序之間通信。

為解決這些問題,在2012年,創(chuàng)建了支付腳本哈希(pay-to-script-hash)P2SH交易。這種交易能讓花費者創(chuàng)建一個公鑰腳本。該公鑰腳本包含第二腳本(redeem 腳本)的哈希值。

P2SH的工作流程,如下圖所示,看起來跟P2PKH幾乎是一樣的。Bob創(chuàng)建一個redeem腳本,可帶有其他任何他要想的腳本,讓后對redeem腳本進行哈希,再把redeem腳本的哈希值提供給Alice。Alice創(chuàng)建一個P2SH類的交易輸出,包含Bob的redeem腳本哈希值。

當Bob想花掉輸出時,他會為簽名腳本提供完整的(可序列化)redeem腳本。比特幣P2P網(wǎng)絡確保redeem腳本的所計算出的哈希值跟Alice輸出中提供的哈希值一樣; 如果它是主要的公鑰腳本,那么它會按其所期望的那樣精確執(zhí)行,如果redeem腳本沒有返回false,就會讓Bob發(fā)掉這個輸出。

spendingP2SH.jpg

Redeem腳本哈希跟公鑰哈希有一樣的屬性 — 因此它可以變換成標準的比特幣地址格式,僅一個小地方跟標準的地址不一樣。這使得收集一個P2SH地址跟一個P2PKH地址一樣同樣簡單。Redeem哈希會混淆Redeem里所有的公鑰,因此P2SH腳本跟P2PKH腳本哈希一樣安全。

標準交易

在早期的比特幣版本,發(fā)現(xiàn)了好幾個危險的bug后,增加了一個測試。該測試僅接受那些公鑰腳本,簽名腳本匹配一個最小安全可信模板集合,且交易其他部分沒有違反另外一個加強網(wǎng)絡的行為規(guī)則小集合的交易。 這就是 isStandard()測試,能通過這個測試的交易被稱之為標準交易

非標準交易 — 這些交易會在上面的測試失敗 — 可以被那些沒有使用比特幣內(nèi)核默認設置的節(jié)點接收。如果這些交易被包含在區(qū)塊中,他們也會回避IsStandard測試,并被處理。

標準交易,除了對那些廣播有害交易的人,提高其攻擊比特幣網(wǎng)絡難度,同時交易測試也實現(xiàn)了:為用戶今天創(chuàng)建新的交易,防止在以后新增一些新的功能時,難度的增大。 比如,如上所述,每個交易包含一個版本號 — 如果用戶肆意的更改版本號, 對于引入一個向后兼容功能時,作為一個工具,它會變的毫無用處。

自比特幣內(nèi)核0.9版本起,標準的公鑰腳本類型如下:

支付公鑰哈希(P2PKH)

P2PKH 是最為通用的公鑰腳本類型,它被用于發(fā)送一個交易到一個或多個比特幣地址。

Pubkey script: OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG 
Signature script: <sig> <pubkey>
支付腳本哈希(P2SH)

P2SH用于發(fā)送一個交易到腳本哈希。 每個標準公鑰腳本能夠被當做一個P2SH redeem腳本, 但是在編碼實踐中,在多個交易類型被標準化后,僅多重簽名(multisig)公鑰腳本有意義。

Pubkey script: OP_HASH160 <Hash160(redeemScript) OP_EQUAL
Signature script: <sig> [sig] [sig...] <redeemScript>
多重簽名

目前,雖然P2SH多重簽名通常被用于多重簽名交易,在UTXO能被花掉前,這個基礎腳本可用于需求多個簽名[?]。

在多重簽名腳本中,被稱之為m-of-n, m是最小數(shù)量匹配公鑰的簽名;n是所提供公鑰數(shù)量。m和n應該是操作符 OP_1OP_16, 他們相對于相應的數(shù)字。

在比特幣實現(xiàn)中,因為考慮兼容的問題,一個一位偏移錯誤必須被保留下來,OP_CHECKMULTISIG會從堆棧消耗掉m所指定個數(shù)值(至少1個),因此,在簽名腳本中的secp256k1簽名列表必須以一個額外值OP_0 , 這個值會消耗掉,但不會被用。

簽名腳本提供的簽名的順序,必須跟公鑰腳本或redeem腳本中的公鑰順序一致。想了解可以查閱OP_CHECKMULTISIG了解更多詳情。

Pubkey script : <m> <a pubkey> [B pubkey] [C pubkey] <n> OP_CHECKMULTISIG
Signature script: OP_0 < A sig> [B sig] [C sig...]

雖然它不是一個可分割的交易類型,這個一個2-of-3的P2SH多重簽名:

Pubkey script: OP_HASH160 <Hash160(redeemScript)> OP_EQUAL
Redeem script: <OP_2> <A pubkey > <B pubkey > < C pubkey > <OP_3> OP_CHEKMULTISIG 
Signature script: OP_O < A sig> < C Sig> <redeemScript>

公鑰

公鑰輸出是一個簡化了的P2PKH公鑰腳本, 但是安全性比不上P2PKH,因此通常他們在新的交易中不再被使用。

Pubkey script: <pubkey> OP_CHECKSIG 
Signature script: <sig>

空數(shù)據(jù)

在默認情況下,比特幣內(nèi)核0.9.0版會轉(zhuǎn)發(fā),處理空數(shù)據(jù)交易類型交易。后來,在一個可證明不可花掉的公鑰腳本加入任意數(shù)據(jù),全節(jié)點不必在他們的UTXO數(shù)據(jù)庫中存儲這些交易。使用空數(shù)據(jù)交易比起那些使UTXO數(shù)據(jù)庫膨脹的交易會更好,因為空數(shù)據(jù)交易不能被自動裁掉;然而,如果有可能的話,把數(shù)據(jù)存儲在交易外面是一個更好的選擇。

假設他們遵守所有其他的共識規(guī)則,那么共識規(guī)則允許空數(shù)據(jù)輸出可達到公鑰腳本所支持的最大10000字節(jié)大小。比如壓入數(shù)據(jù)的大小不會超過520字節(jié)。

在默認情況下,比特幣內(nèi)核0.9.x 到 0.10.x 會轉(zhuǎn)發(fā),處理空數(shù)據(jù)交易,在單個壓入數(shù)據(jù)最大在40字節(jié),且只有一個只支付0 satoshis空數(shù)據(jù)輸出.

Pubkey Script: OP_RETURN <0 to 40 bytes of data>
(Null data scripts cannot be spent, so there's no signature script.)

在保持其他規(guī)則不變的情況下,比特幣內(nèi)核 0.11.x把默認大小增加到80個字節(jié)。

假設在不超過總字節(jié)的前提下,比特幣內(nèi)核0.12.0默認會轉(zhuǎn)發(fā),處理任意數(shù)量,小于83字節(jié)的數(shù)據(jù)壓入的空數(shù)據(jù)輸出。同時必須僅有一個支付 0 satoshis的空數(shù)據(jù)輸出。

-datacarriersize比特幣內(nèi)核配置選項,可以允許你設置比特幣內(nèi)核可轉(zhuǎn)發(fā),可處理的空數(shù)據(jù)輸出最大字節(jié)數(shù)。

非標準交易

如果你在輸出中使用任何非標準公鑰腳本,那些使用默認設置的比特幣節(jié)點,礦工不會接收,廣播,處理你的交易。 當你試圖廣播你的交易到一個使用默認設置的比特幣節(jié)點時,你會收到一個錯誤。

如果你創(chuàng)建一個redeem腳本,并做哈希處理,把哈希值用在一個P2SH輸出里,比特幣網(wǎng)絡只會看到這個哈希值,因此不管redeem腳本內(nèi)容是什么,比特幣網(wǎng)絡都會認為這個輸出是有效的。這就允許對非標準腳本執(zhí)行支付,從比特幣內(nèi)核0.11起,幾乎所有的有效redeem腳本都可以被花掉,除了使用了NOP操作符的腳本。這些操作符是為未來軟分叉而預留的,并只被那些沒有準守標準內(nèi)存池策略的節(jié)點轉(zhuǎn)發(fā),處理。

注意:標準交易是用來保護,幫助整個比特幣網(wǎng)絡,而不是防止你犯錯的。創(chuàng)建一個可以讓satoshi變成不可使用是一件非常容易的事情。

從比特幣內(nèi)核0.9.3起,標準交易必須滿足以下幾個條件:

  • 交易必須完成: 要么它的鎖定時間必須過去的某個時間,或其所在區(qū)塊的區(qū)塊高度必須少于等于當前區(qū)塊高度,要么其他序列號都是0xffffffff。

  • 交易大小必須小于100,000個字節(jié)。這大約是200多個典型單輸入,單輸出P2PKH交易的大小。

  • 每個交易的簽名腳本大小必須小于1650個字節(jié)。在P2SH交易中,這足夠可以容納15-of-15個使用壓縮公鑰的多重簽名。

  • 需要至少3個公鑰的空(非P2SH)多重簽名交易不再是標準交易。

  • 交易的簽名腳本只能把數(shù)據(jù)壓入腳本求值堆棧。它不能壓入新的操作符,除了那些僅壓入數(shù)據(jù)到堆棧的操作符。

  • 交易不可以包含:其輸出中的satoshi數(shù)量,少于在一個典型的輸入中,通常要花掉satoshi總量的1/3 的任何輸出。 在一個默認設置的比特幣節(jié)點,在目前,一個P2PKH或P2SH輸出要花費546個satoshi。 有個例外: 標準空數(shù)據(jù)輸出必須只接收0個satoshi。

簽名哈希類型

OP_CHECKSIG會從每個它要求值的簽名中取出一個非堆棧參數(shù),允許簽名者決定交易的哪些部分需要 簽名。因為簽名可以防止這些交易的部分被修改,這也可以讓簽名者有選擇的讓其他人修改他們的交易。

這些各種各樣要被簽名的選項就叫做簽名哈希類型。目前有三種可用的基本SIGHASH類型:

  • SIGHASH_ALL, 這是默認選項,它會對所有的輸入,輸出進行簽名,防止所有數(shù)據(jù)被修改,除了簽名腳本。

  • SIGHASH_NONE 對所有的輸入進行簽名,但不對任何輸出簽名,這允許任何人修改satoshi的去向,除非其他簽名使用其他簽名哈希標志來保護輸出。

  • SIGHASH_SINGLE 僅對跟輸入相對應的輸出進行簽名(輸出的輸出索引號跟輸入的索引號一樣),確保沒有人能改變交易中屬于你的那部分,但允許其他簽名者可以修改交易中屬于他們的那部分。相應的輸出必須存在,或被簽上數(shù)值“1”,以突破簽名安全方案。這里的輸入跟其他輸入一樣,都被包含在簽名里面。其他沒有包含在簽名里面的輸入的序列號是可以被更新的。

使用SIGHASH_ANYONECANPAY(任何人可以支付)標志可以修改這些基本類型。有如下三種組合:

  • SIGHASH_ALL|SIGHASH_ANYONECANPAY 對所以輸出簽名,但僅對一個輸入簽名,同時允許任何人添加,刪除其他輸入,因此任何人可以貢獻額外的satoshi,但不能改變發(fā)送satoshi的數(shù)量,以及目的地。

  • SIGHASH_NONE|SIGHASH_ANYONECANPAY僅對一個輸入簽名,同時允許任何人添加,刪除輸入,輸出,因此任何獲得該交易拷貝人都可以自由地把它花掉。

  • SIGHASH_SINGLE|SIGHASH_ANYONECANPAY 簽名一個輸入且與其相對應的輸出。允許任何人添加,刪除其他輸入。

因為每個輸入都被簽名,一個有多個輸入的交易,其不同部分可以用多個簽名哈希類型來簽名。例如,一個用NONE簽名單輸入交易可以讓把它添加到區(qū)塊鏈的礦工修改其輸出。另一方面,如果一個帶有兩個輸入的交易有一個輸入使用NONE來簽名,另外一個使用All來簽名,這個All簽名者可以在不要跟NONE簽名者商議,就可以選擇怎么花掉satoshi。 但是其他任何人不能修改這個交易。

鎖定時間和序列號

所有簽名類型要簽名的數(shù)據(jù)是:交易的鎖定時間。(在比特幣內(nèi)核源碼中是:mLockTime) 鎖定時間表示交易最早能加入到區(qū)塊鏈的時間。

鎖定時間允許簽名者創(chuàng)建時間鎖定交易。 這種交易僅在未來的某個時間才會有效,這給簽名者一個改變他們想法的機會。

如果任何簽名者改變他們的想法,他們能創(chuàng)建一個新的非鎖定時間交易。這個新的交易,作為之前交易的輸入,會使用之前鎖定交易的輸出作為其輸出。在鎖定時間到期之前,如果這個新的交易被添加到區(qū)塊鏈,就使之前的鎖定交易無效。

之前的比特幣內(nèi)核版本提供了一個功能,可以防止交易簽名者使用上面的方法取消時間鎖定交易,但為了防止拒絕訪問攻擊,這個功能一個必要的部分已被禁止。這個系統(tǒng)中遺留部分是每個輸入中的4字節(jié)序列號。 序號號意味著允許多個簽名者同意更新一個交易。當他們完成交易更新后,他們可以同意把每個輸入的序列號設置成0xffffffff(4字節(jié)無符號) - 這可以允許交易加入到區(qū)塊鏈中,即便鎖定時間還沒到期。

即使到今天,把所有序列號設置成0xffffffff(在比特幣內(nèi)中,默認是這個值)可以禁止掉所有的時間鎖,因此如果你想是一個時間鎖,至少一個輸入的序列號是小于0xffffffff的。因為序列號沒有其他用途,所有把序列號設置成0就可以開啟時間鎖。

mLockTime是一個無符號4字節(jié)整型數(shù)字,其可以通過兩種方式來解析:

  • 如果小于50億,mLockTime就被解析成區(qū)塊高度。這個交易就可被添加到任何等于,或高于這個區(qū)塊高度的區(qū)塊中。

  • 如果大于等于50億,mLockTime就以Unix epoch(從1970-1-1 00:00 UTC時間起,到現(xiàn)在過去的秒數(shù),到目前為止有13.95億秒) 時間格式來解析。這個交易就可被加入任何區(qū)塊時間大于mLockTime的區(qū)塊中。

交易費用和零錢

交易費用的支付是基于簽名交易字節(jié)太小來計算。每個字節(jié)的費用是基于,在被挖出區(qū)塊其所占空間來計算,需求的空間越大,費用就越高。在區(qū)塊鏈章節(jié)中所述,交易費用是給礦工的,因此最終是由每個礦工來決定選擇最低的交易費用。

有一個”高優(yōu)先級交易“的概念,它可以花掉那些長時間沒有用過的satoshis。[?]

在一起,這些”優(yōu)先“交易通常可以不需交易費。在比特幣內(nèi)核0.12前,每個區(qū)塊會高優(yōu)先級交易預留50kb空間,然而,現(xiàn)在默認設置成0kb。在優(yōu)先級區(qū)域后,所有交易按他們每字節(jié)費用來按序排列,高費用的交易優(yōu)先會被加到隊列中,直到可用空間填滿。

自從比特幣內(nèi)核0.9版本后,在比特幣網(wǎng)絡中,廣播一個交易需要支付一筆最小費用(目前是1000satoshi)。在區(qū)塊有足夠多用的空間前,任何支付這個最小費用的交易要準備好等很長一段時間。這非常重要,想知道為什么,請看支付驗證章節(jié).

因為每個交易花UTXO,且因為一個UTXO只能被使用一次,UTXO里面的satoshi必須一次使用完,或作為交易費用。UTXO里面的satoshi數(shù)量跟其他要支付的一樣多是很少見的,因此會有多個交易包含到一個零錢輸出。

零錢輸出是正規(guī)的輸出。它把那些零散的satoshi從UTXO轉(zhuǎn)到花費者。他們能重用UTXO里面的P2PHK公鑰哈希或P2SH腳本哈希,但是我們會在下一小節(jié)所講述,強烈建議把零錢輸出發(fā)送到一個新的P2PKH或P2SH地址。

避免密鑰重用

在一個交易中,支付者,接受者可以查看交易中所用到的所有公鑰或者地址。這可以運行任意一方使用公共的區(qū)塊鏈來跟蹤這個地址或公鑰過去,未來所有的交易。

如果同一個公鑰被經(jīng)常使用,比如人們使用比特幣地址(公鑰哈希)作為一個固定的支付地址,其他人就可以很容易的跟蹤這個人支付,接受的習慣,包括已知掌控的地址中有多少比特幣。

其實我們不必如此。如果一個公鑰只使用兩次,一次用來接受付款,一次用來花掉這次的付款,這樣用戶就可以獲得極大的財務隱私。

更好的辦法是,當在接收支付或者創(chuàng)建輸出時,可使用新的公鑰或者獨一無二的地址跟其他技術(后續(xù)會講到)結(jié)合起來,比如CoinJoin或者避免混合,就可以提高使用區(qū)塊鏈來跟著用戶如何接收,花掉他們比特幣的難度。

避免密鑰重用也可以提高安全防護,比如通過公鑰(假設的),或簽名比對(在當今,如下特定環(huán)境下,會有更多常規(guī)攻擊的假設)來實現(xiàn)重建私鑰。

  1. 獨一無二的(非重用)P2PKH,P2SH地址可防止第一個類型攻擊,其通過隱藏ECSDA公鑰(被哈希處理過的),直到第一次發(fā)送到這些地址的satoshi被花掉,因此攻擊實際上是無用的,除非他們能在1,2個小時內(nèi)重建私鑰,這很好的通過區(qū)塊鏈網(wǎng)絡保護了交易。

  2. 獨一無二的(非重用)私鑰可以防止第二種類型攻擊,其通過僅為每個私鑰生成一個簽名,因此在對比攻擊中,攻擊者永遠無法獲得后續(xù)的簽名。當今,現(xiàn)存的比對攻擊,在簽名是,沒有足夠的熵可用時,或熵使用通過別的方式被暴露了,比如邊信道攻擊.

因此,出于對于隱私,安全的考慮,在你構(gòu)建應用程序時,不管什么時候,鼓勵盡可能的避免公鑰重用,組織用戶重要比特幣地址。如果你的應用程序需要提供一個固定的URI,用于接受付款,請看下面的bitcoin:[URL章節(jié)](https://bitcoin.org/en/developer-guide#bitcoin-uri)。

交易延展性

任何比特幣簽名哈希類型都不會保護簽名腳本,這會導致給有限的拒絕服務攻擊開啟了一扇門,這就叫做交易延展性。簽名腳本包含secp256k1簽名,secp256k1簽名是不能給自己簽名的,這就讓攻擊者可以對交易做非功能修改,這也不會讓交易失效。比如,攻擊者可以在簽名腳本中加入一些數(shù)據(jù)。這些簽名腳本在之前公鑰腳本被處理前會被丟掉。

雖然這些修改是非功能性的修改 — 因此他們即不會改變交易輸入,也不會修改交易輸出 — 不過他們的確會改名交易的哈希值。因為每個交易會使用哈希值(作為交易id txid)來鏈接到之前的交易,一個被修改過的交易其txid跟其創(chuàng)建者txid就不一樣了。

這對于立馬加入到區(qū)塊鏈中的交易,這不是個問題。但是當在交易被加入到區(qū)塊鏈之前,交易輸出被花掉時,就成問題了。

比特幣開發(fā)者已經(jīng)致力于減少標準交易之間為交易的延展性,其他的一個成果是:BIP141:SegWit隔離見證。這個功能已被比特幣內(nèi)核支持,并在2017.8月激活。當隔離見證不被使用時,新的交易不應依賴于之前還沒有加入到區(qū)塊鏈中的交易,特別是有大量的satoshi需要緊急處理時。

交易的延展性也會影響支付攻擊。比特幣內(nèi)核RPC(遠程調(diào)用)接口可以讓你通過他們的交易ID(txid)跟蹤交易, 但是如果交易id改變了,因為交易被修改了,它就會看起來像交易從網(wǎng)絡中消失了。

當前交易跟蹤最佳實踐告訴我們交易應該通過交易輸出(UTXO 它以輸入的方式被花掉)來跟蹤,因為不讓交易無效,是無法更改UTXO的。

更進一步的最佳實踐向我們明示了,如果一個交易看起來從網(wǎng)絡中消失了,那么需要通過讓丟失的交易無效后,在重發(fā)交易。有一個辦法總是可行的,就是確保重發(fā)的支付花掉同樣的交易輸出(在丟失交易中作為交易輸入)。


聲明:

文中帶有[?]的地方,表示我對此翻譯明顯感覺不太對的,后續(xù)會不斷修正。

初次翻譯,可能會有些地方翻譯的不好,不地道,甚至錯誤,如果有發(fā)現(xiàn),還請留言,指出,以便我好修正,謝謝!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容