1. 程式人生 > >比特幣學習筆記——————5、 交易

比特幣學習筆記——————5、 交易


5.1 簡介

比特幣交易是比特幣系統中最重要的部分。根據比特幣系統的設計原理,系統中任何其他的部分都是為了確保比特幣交易可以被生成、能在比特幣網路中得以傳播和通過驗證,並最終新增入全球比特幣交易總賬簿(比特幣區塊鏈)。比特幣交易的本質是資料結構,這些資料結構中含有比特幣交易參與者價值轉移的相關資訊。比特幣區塊鏈是全球複式記賬總賬簿,每個比特幣交易都是在比特幣區塊鏈上的一個公開記錄。

在這一章,我們將會剖析比特幣交易的多種形式、所包含的資訊、如何被建立、如何被驗證以及如何成為所有比特幣交易永久記錄的一部分。

5.2 比特幣交易的生命週期

一筆比特幣交易的生命週期起始於它被建立的那一刻,也就是誕生(origination)。 隨後,比特幣交易會被一個或者多個簽名加密,這些簽名標誌著對該交易指向的比特幣資金的使用許可。接下來,比特幣交易被廣播到比特幣網路中。在比特幣網路中,每一個節點(比特幣交易參與者)驗證、並將交易在網路中進行廣播,直到這筆交易被網路中大多數節點接收。最終,比特幣交易被一個挖礦節點驗證,並被新增到區塊鏈上一個記錄著許多比特幣交易的區塊中。

一筆比特幣交易一旦被記錄到區塊鏈上並被足夠多的後續區塊確認,便成為比特幣總賬簿的一部分,並被所有比特幣交易參與者認可為有效交易。於是,被這筆交易分配到一個新所有者名下的比特幣資金可以在新的交易中被使用——這使得所有權鏈得以延伸且再次開啟一個新的比特幣交易生命週期。

5.2.1 建立比特幣交易

將一筆比特幣交易理解成紙質支票或許有助於加深我們對它的理解。與支票相似,一筆比特幣交易其實是一個有著貨幣轉移目的的工具,這個工具只有在交易被執行時才會在金融體系中體現,而且交易發起人並不一定是簽署該筆交易的人。

比特幣交易可以被任何人在線上或線下建立,即便建立這筆交易的人不是這個賬戶的授權簽字人。比如,一個負責應付賬款的櫃員在處理應付票據時可能會需要CEO簽名。相似地,這個負責應付賬款的櫃員可以建立比特幣交易,然後讓CEO對它進行數字簽名,從而使之有效。一張支票是指定一個特定賬戶作為資金來源的,但是比特幣交易指定以往的一筆交易作為其資金來源,而不是一個特定賬戶。

一旦一筆比特幣交易被建立,它會被資金所有者(們)簽名。如果它是合法建立並簽名的,則該筆交易現在就是有效的,它包含了轉移這筆資金所需要的所有資訊。最終,有效的比特幣交易必須能接入比特幣網路,從而使之能被傳送,直至抵達下一個登記在公共總賬薄(區塊鏈)的挖礦節點。

5.2.2 廣播交易至比特幣網路

首先,一筆交易需要傳遞至比特幣網路,才能被傳播,也才能加入區塊鏈中。本質上,一筆比特幣交易只是300到400位元組的資料,而且它們必須被髮送到成千上萬個比特幣節點中的任意一個。只要傳送者能使用多於一個比特幣節點來確保這筆交易被傳播,那麼傳送者並不需要信任用來傳播該筆交易的單一節點。相應地,這些節點不需要信任傳送者,也不用建立傳送者的“身份檔案”。由於這筆交易是經過簽名且不含任何機密資訊、私鑰或密碼,因此它可被任何潛在的便利網路公開地傳播。信用卡交易包含敏感資訊,而且依賴加密網路連線完成資訊傳輸,但比特幣交易可在任意網路環境下被髮送。只要這筆交易可以到達能將它廣播到比特幣網路的比特幣節點,這筆交易是如何被傳輸至第一個節點的並不重要。

比特幣交易因此可以通過未加密網路(例如WiFi、藍芽、NFC、ChirP、條形碼或者複製貼上至一個網頁表格)被髮送到比特幣網路。在一些極端情況下,一筆比特幣交易可以通過封包無線電、衛星或短波、擴頻或跳頻以避免被偵測或阻塞通訊的方式進行傳輸。一筆比特幣交易甚至可被編為文字資訊中的表情符號並被髮表到線上論壇,或被髮送成一條簡訊或一條Skype聊天資訊。因為比特幣將金錢變成了一種資料結構,所以在本質上是不可能阻止任何人建立並執行比特幣交易的。

5.2.3 比特幣交易在比特幣網路中的傳播

一旦一筆比特幣交易被髮送到任意一個連線至比特幣網路的節點,這筆交易將會被該節點驗證。如果交易被驗證有效,該節點將會將這筆交易傳播到這個節點所連線的其他節點;同時,交易發起者會收到一條表示交易有效並被接受的返回資訊。如果這筆交易被驗證為無效,這個節點會拒絕接受這筆交易且同時返回給交易發起者一條表示交易被拒絕的資訊。

比特幣網路是一個點對點網路,這意味著每一個比特幣節點都連線到一些其他的比特幣節點(這些其他的節點是在啟動點對點協議時被發現的)。整個比特幣網路形成了一個鬆散地連線、且沒有固定拓撲或任何結構的“蛛網”——這使得所有節點的地位都是同等的。比特幣交易相關資訊(包括交易和區塊)被傳播——從每一個節點到它連線的其他節點。一筆剛通過驗證且並被傳遞到比特幣網路中任意節點的交易會被髮送到三到四個相鄰節點,而每一個相鄰節點又會將交易傳送到三至四個與它們相鄰的節點。以此類推,在幾秒鐘之內,一筆有效的交易就會像指數級擴散的波一樣在網路中傳播,直到所有連線到網路的節點都接收到它。

比特幣網路被設計為能高效且靈活地傳遞交易和區塊至所有節點的模式,因而比特幣網路能抵禦入侵。為了避免垃圾資訊的濫發、拒絕服務攻擊或其他針對比特幣系統的惡意攻擊,每一個節點在傳播每一筆交易之前均進行獨立驗證。 一個異常交易所能到達的節點不會超過一個。"8.3 交易的獨立校驗"一節將詳細介紹決定比特幣交易是否有效的原則。

5.3 交易結構

一筆比特幣交易是一個含有輸入值和輸出值的資料結構,該資料結構植入了將一筆資金從初始點(輸入值)轉移至目標地址(輸出值)的程式碼資訊。比特幣交易的輸入值和輸出值與賬號或者身份資訊無關。你應該將它們理解成一種被特定祕密資訊鎖定的一定數量的比特幣。只有擁有者或知曉這個祕密資訊的人可以解鎖。一筆比特幣交易包含一些欄位,如表5-1所示。

表5-1 交易結構

大小欄位描述
4位元組版本明確這筆交易參照的規則
1-9位元組輸入數量被包含的輸入的數量
不定輸入一個或多個交易輸入
1-9位元組輸出數量被包含的輸出的數量
不定輸出一個或多個交易輸出
4位元組時鐘時間一個UNIX時間戳或區塊號

交易的鎖定時間

鎖定時間定義了能被加到區塊鏈裡的最早的交易時間。在大多數交易裡,它被設定成0,用來表示立即執行。如果鎖定時間不是0並且小於5億,就被視為區塊高度,意指在這個指定的區塊高度之前,該交易沒有被包含在區塊鏈裡。如果鎖定時間大於5億,則它被當作是一個Unix紀元時間戳(從1970年1月1日以來的秒數),並且在這個指定時點之前,該交易沒有被包含在區塊鏈裡。鎖定時間的使用相當於將一張紙質支票的生效時間予以後延。

5.4 交易的輸出和輸入

比特幣交易的基本單位是未經使用的一個交易輸出,簡稱UTXO。UTXO是不能再分割、被所有者鎖住或記錄於區塊鏈中的並被整個網路識別成貨幣單位的一定量的比特幣貨幣。比特幣網路監測著以百萬為單位的所有可用的(未花費的)UTXO。當一個使用者接收比特幣時,金額被當作UTXO記錄到區塊鏈裡。這樣,一個使用者的比特幣會被當作UTXO分散到數百個交易和數百個區塊中。實際上,並不存在儲存比特幣地址或賬戶餘額的地點,只有被所有者鎖住的、分散的UTXO。“一個使用者的比特幣餘額”,這個概念是一個通過比特幣錢包應用建立的派生之物。比特幣錢包通過掃描區塊鏈並聚合所有屬於該使用者的UTXO來計算該使用者的餘額。


在比特幣的世界裡既沒有賬戶,也沒有餘額,只有分散到區塊鏈裡的UTXO。

一個UTXO可以是一“聰”的任意倍。就像美元可以被分割成表示兩位小數的“分”一樣,比特幣可以被分割成表示八位小數的“聰”。儘管UTXO可以是任意值,但只要它被創造出來了,就像不能被切成兩半的硬幣一樣不可再分了。如果一個UTXO比一筆交易所需量大,它仍會被當作一個整體而消耗掉,但同時會在交易中生成零頭。例如,你有20比特幣的UTXO並且想支付1比特幣,那麼你的交易必須消耗掉整個20比特幣的UTXO並且產生兩個輸出:一個是支付了1比特幣給接收人,另一個是支付19比特幣的找零到你的錢包。這樣的話,大部分比特幣交易都會產生找零。

想象一下,一位顧客要買1.5元的飲料。她掏出她的錢包並努力從所有硬幣和鈔票中找出一種組合來湊齊她要支付的1.5元。如果可能的話,她會選剛剛好的零錢(比如一張1元紙幣和5個一毛硬幣)或者是小面額的組合(比如3個五毛硬幣)。如果都不行的話,她會用一張大面額的鈔票,比如5元紙幣。如果她把過多的錢,比如5元,給了商店老闆,她會拿到3.5元的找零,並把找零放回她的錢包以供未來使用。

類似的,一筆比特幣交易可以有任意數值,但必須從使用者可用的UTXO中創建出來。使用者不能再把UTXO進一步細分,就像不能把一元紙幣撕開而繼續當貨幣使用一樣。使用者的錢包應用通常會從使用者可用的UTXO中選取多個可用的個體來拼湊出一個大於或等於一筆交易所需的比特幣量。

就像現實生活中一樣,比特幣應用可以使用一些策略來滿足付款需要:組合若干小的個體,算出準確的找零;或者使用一個比交易值大的個體然後進行找零。所有這些複雜的、由可支付的UTXO完成的組合,都是由使用者的錢包自動完成,並不為使用者所見。只有當你以程式設計方式用UTXO來構建原始交易時,這些才與你有關。

被交易消耗的UTXO被稱為交易輸入,由交易建立的UTXO被稱為交易輸出。通過這種方式,一定量的比特幣價值在不同所有者之間轉移,並在交易鏈中消耗和建立UTXO。一筆比特幣交易通過使用所有者的簽名來解鎖UTXO,並通過使用新的所有者的比特幣地址來鎖定並建立UTXO。

對於輸出和輸入鏈來說,有一個例外,它是一種特殊的交易型別,稱為Coinbase交易。這是每個區塊中的首個交易。這種交易存在的原因是作為對挖礦的獎勵而產生全新的可用於支付的比特幣給“贏家”礦工。這也就是為什麼比特幣可以在挖礦過程中被創造出來,我們將在第8章中進行詳述。


輸入和輸出,哪一個是先產生的呢?先有雞還是先有蛋呢?嚴格來講,先產生輸出,因為可以創造新比特幣的coinbase交易沒有輸入,但它可以無中生有地產生輸出。

5.4.1 交易輸出

每一筆比特幣交易創造輸出,輸出都會被比特幣賬簿記錄下來。除特例之外(見“5.7.4 資料輸出(OP_RETURN操作符)”),幾乎所有的輸出都能創造一定數量的可用於支付的比特幣,也就是UTXO。這些UTXO被整個網路識別,並且所有者可在未來的交易中使用它們。給某人傳送比特幣實際上是創造新的UTXO,註冊到那個人的地址,並且能被他用於新的支付。

UTXO被每一個全節點比特幣客戶端在一個儲存於記憶體中的資料庫所追蹤,該資料庫也被稱為“UTXO集”或者“UTXO池”。新的交易從UTXO集中消耗(支付)一個或多個輸出。

交易輸出包含兩部分:

▷ 一定量的比特幣,被命名為“聰”,是最小的比特幣單位; 
一個鎖定指令碼,也被當作是“障礙”,提出支付輸出所必須被滿足的條件以“鎖住”這筆總額。

在前面的鎖定指令碼中提到的這個交易指令碼語言會在後面121頁的“交易指令碼和指令碼語言”一節中詳細討論。表5-2列出了交易輸出的結構。

表5-2 交易輸出結構

尺寸欄位說明
8個位元組總量用聰表示的比特幣值(10-8比特幣)
1–9個位元組(可變整數)鎖定指令碼尺寸用位元組表示的後面的鎖定指令碼長度
變長鎖定指令碼一個定義了支付輸出所需條件的指令碼

在例5-1中,我們使用blockchain.info應用程式介面來查詢特定地址的UTXO。

例5-1 一個呼叫blockchain.info應用程式介面來查詢與一個地址有關的UTXO的指令碼

# 從blockchain API中得到未花費的輸出

import json
import requests

# 樣例地址
address = '1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX'

# API網址是:https://blockchain.info/unspent?active=<address>
# 它返回一個JSON物件,其中包括一個包含著UTXO的“unspent_outputs”列表,就像這樣:
#{      "unspent_outputs":[
    #{ 
#       tx_hash":"ebadfaa92f1fd29e2fe296eda702c48bd11ffd52313e986e99ddad9084062167",
#      "tx_index":51919767,
#      "tx_output_n": 1,
#      "script":"76a9148c7e252f8d64b0b6e313985915110fcfefcf4a2d88ac",
#      "value": 8000000,
#      "value_hex": "7a1200",
#      "confirmations":28691
#   },
# ...
#]} 

resp = requests.get('https://blockchain.info/unspent?active=%s' % address)
utxo_set = json.loads(resp.text)["unspent_outputs"]

for utxo in utxo_set:
    print "%s:%d - %ld Satoshis" % (utxo['tx_hash'], utxo['tx_output_n'], utxo['val 
ue'])

執行指令碼,我們將會得到“交易ID,冒號,特定UTXO的索引號,以及這個UTXO包含的聰的數額”的列表。在例5-2中,鎖定指令碼被省略了。

例5-2 執行 get-utxo.py指令碼

$ python get-utxo.py
ebadfaa92f1fd29e2fe296eda702c48bd11ffd52313e986e99ddad9084062167:1 - 8000000 Satoshis
6596fd070679de96e405d52b51b8e1d644029108ec4cbfe451454486796a1ecf:0 - 16050000 Satoshis
74d788804e2aae10891d72753d1520da1206e6f4f20481cc1555b7f2cb44aca0:0 - 5000000 Satoshis
b2affea89ff82557c60d635a2a3137b8f88f12ecec85082f7d0a1f82ee203ac4:0 - 10000000 Satoshis
...

支付條件(障礙)

交易輸出把用聰表示的一定數量的比特幣,和特定的定義了支付輸出所必須被滿足的條件的障礙,或者叫鎖定指令碼,關聯到了一起。在大多數情況下,鎖定指令碼會把輸出鎖在一個特定的比特幣地址上,從而把一定數量的比特幣的所有權轉移到新的所有者上。當Alice在Bob的咖啡店為一杯咖啡付款時,Alice的交易創造了0.015比特幣的輸出,在咖啡店的比特幣地址上成為一種障礙,或者說是被鎖在了咖啡店的比特幣地址上。那0.015比特幣輸出被記錄到區塊鏈中,並且成為UTXO的一部分,也就是作為可用餘額出現在Bob的錢包裡。當Bob選擇使用這筆款項進行支付時,他的交易會釋放障礙,通過提供一個包含Bob私鑰的解鎖指令碼來解鎖輸出。

5.4.2 交易輸入

簡單地說,交易輸入是指向UTXO的指標。它們指向特定的UTXO,並被交易雜湊和在區塊鏈中記錄UTXO的序列號作為參考。若想支付UTXO,一個交易的輸入也需要包含一個解鎖指令碼,用來滿足UTXO的支付條件。解鎖指令碼通常是一個簽名,用來證明對於在鎖定指令碼中的比特幣地址擁有所有權。

當用戶付款時,他的錢包通過選擇可用的UTXO來構造一筆交易。比如說,要支付0.015比特幣,錢包應用會選擇一個0.01 UTXO和一個0.005 UTXO,使用它們加在一起來得到想要的付款額。

在例5-3中,我們展示了一種貪心演算法來為了得到特定的付款額而選擇可用的UTXO。在例中,可用的UTXO被提供在一個常數陣列中。但在實際中,可用的UTXO被一個遠端過程呼叫比特幣核心,或者被一個如例5-1中的第三方應用程式介面,來檢索出來。

例5-3 一個計算會被髮送的比特幣總量的指令碼

# 使用貪心演算法從UTXO列表中選擇輸出。

from sys import argv 

class OutputInfo: 

    def __init__(self, tx_hash, tx_index, value): 
        self.tx_hash = tx_hash
        self.tx_index = tx_index
        self.value = value 

    def __repr__(self):
        return "<%s:%s with %s Satoshis>" % (self.tx_hash, self.tx_index, 
                                            self.value) 

# 為了傳送,從未花費的輸出列表中選出最優輸出。
# 返回輸出列表,並且把其他的改動傳送到改變地址。
def select_outputs_greedy(unspent, min_value): 
    # 如果是空的話認為是失敗了。
    if not unspent: return None 
    # 分割成兩個列表。
    lessers = [utxo for utxo in unspent if utxo.value < min_value]     greaters = [utxo for utxo in unspent if utxo.value >= min_value] 
    key_func = lambda utxo: utxo.value
    if greaters: 
        # 非空。尋找最小的greater。
        min_greater = min(greaters)
        change = min_greater.value - min_value 
        return [min_greater], change 
    # 沒有找到greaters。重新嘗試若干更小的。
    # 從大到小排序。我們需要儘可能地使用最小的輸入量。
    lessers.sort(key=key_func, reverse=True)
    result = []
    accum = 0
    for utxo in lessers: 
        result.append(utxo)
        accum += utxo.value
        if accum >= min_value: 
            change = accum - min_value
            return result, "Change: %d Satoshis" % change 
    # 沒有找到。
    return None, 0 

def main(): 
    unspent = [ 
        OutputInfo("ebad
faa92f1fd29e2fe296eda702c48bd11ffd52313e986e99ddad9084062167", 1,  8000000),
        OutputIn
fo("6596fd070679de96e405d52b51b8e1d644029108ec4cbfe451454486796a1ecf", 0, 16050000),
        OutputInfo("b2af
fea89ff82557c60d635a2a3137b8f88f12ecec85082f7d0a1f82ee203ac4", 0,  10000000),
        OutputIn
fo("7dbc497969c7475e45d952c4a872e213fb15d45e5cd3473c386a71a1b0c136a1", 0, 25000000),
        OutputIn
fo("55ea01bd7e9afd3d3ab9790199e777d62a0709cf0725e80a7350fdb22d7b8ec6", 17, 5470541),
        OutputIn
fo("12b6a7934c1df821945ee9ee3b3326d07ca7a65fd6416ea44ce8c3db0c078c64", 0, 10000000),
        OutputIn
fo("7f42eda67921ee92eae5f79bd37c68c9cb859b899ce70dba68c48338857b7818", 0, 16100000),
    ] 

    if len(argv) > 1:
        target = long(argv[1]) 
    else:
        target = 55000000 

    print "For transaction amount %d Satoshis (%f bitcoin) use: " % (target, target/ 10.0**8) 
    print select_outputs_greedy(unspent, target) 

if __name__ == "__main__": 
    main()

如果我們不使用引數執行select-utxo.py指令碼,它會試圖為一筆五千五百萬聰(0.55比特幣)的付款構造一組UTXO。如果你提供一個指定的付款額作為引數,指令碼會選擇UTXO來完成指定的付款額。在例5-4中,我們執行指令碼來試著完成一筆0.5比特幣,或者說是五千萬聰的付款。

例5-4 執行select-utxo.py

$ python select-utxo.py 50000000
For transaction amount 50000000 Satoshis (0.500000 bitcoin) use:
([<7dbc497969c7475e45d952c4a872e213fb15d45e5cd3473c386a71a1b0c136a1:0 with 25000000
Satoshis>, <7f42eda67921ee92eae5f79bd37c68c9cb859b899ce70dba68c48338857b7818:0 with 16100000 Satoshis>,
<6596fd070679de96e405d52b51b8e1d644029108ec4cbfe451454486796a1ecf:0 with 16050000 Satoshis>], 'Change: 7150000 Satoshis')

一旦UTXO被選中,錢包會為每個UTXO生成包含簽名的解鎖指令碼,由此讓它們變得可以通過滿足鎖定指令碼的條件來被支付。錢包把這些UTXO作為參考,並且連同解鎖指令碼一起作為輸入加到交易中。表5-3展示了交易輸入的結構。

表5-3 交易輸入的結構

尺寸欄位說明
32個位元組交易指向交易包含的被花費的UTXO的雜湊指標
4個位元組輸出索引被花費的UTXO的索引號,第一個是0
1–9個位元組(可變整數)解鎖指令碼尺寸用位元組表示的後面的解鎖指令碼長度
變長解鎖指令碼一個達到UTXO鎖定指令碼中的條件的指令碼
4個位元組序列號目前未被使用的交易替換功能,設成0xFFFFFFFF

序列號是用來覆蓋在交易鎖定時間之前失效的交易,這是一專案前沒有在比特幣中用到的功能。大多數交易把這個值設定成最大的整數(0xFFFFFFFF)並且被比特幣網路忽略。如果一次交易有非零的鎖定時間,那麼它至少需要有一個序列號比0xFFFFFFFF低的輸入來啟用鎖定時間。

5.4.3 交易費

大多數交易包含交易費,這是為了在網路安全方面給比特幣礦工一種補償。在第8章中,對於挖礦、費用和礦工得到的獎勵,有更詳細的討論。這一節解釋交易費是如何被包含在日常交易中的。大多數錢包自動計算並計入交易費。但是,如果你程式設計構造交易,或者使用命令列介面,你必須手動計算並計入這些費用。

交易費可當作是為了包含(挖礦)一筆交易到下一個區塊中的一種鼓勵,也可當作是對於欺詐交易和任何種類的系統濫用,在每一筆交易上通過徵收一筆小成本的稅而造成的一種妨礙。交易費被挖出這個區塊的礦工得到,並且記錄在這個交易的區塊鏈中。

交易費基於交易的尺寸,用千位元組來計算,而不是比特幣的價值。總的來說,交易費基於市場所設定,生效於比特幣網路中。礦工依據許多不同的標準,按重要性對交易進行排序,這包括費用,並且甚至可能在某種特定情況下免費處理交易。交易費影響處理優先順序,這意味著有足夠費用的交易會更可能地被包含在下一個挖出的區塊中;與此同時,交易費不足或者沒有交易費的交易可能會被推遲,基於盡力而為的原則在幾個區塊之後被處理,甚至可能根本不被處理。交易費不是強制的,而且沒有交易費的交易也許最終會被處理,但是,包含交易費將提高處理優先順序。

隨著時間的過去,交易費的計算方式和交易費在交易優先順序上的影響一直在發展。起初,交易費是網路中的一個固定常數。漸漸地,交易費的結構被放寬了,以便被市場基於網路容量和交易量而強制影響。目前最小交易費被固定在每千位元組0.0001比特幣,或者說是每千位元組萬分之一比特幣,最近一次改變是從千分之一比特幣減少到這個數值的。大多數交易少於一千位元組,但是那些包含多個輸入和輸出的交易尺寸可能更大。在未來的比特幣協議修訂版中,錢包應用預計會使用統計學分析,基於最近的幾筆交易的平均費用,來計算最恰當的費用並附在交易上。

目前礦工使用的,對包含在一個區塊中的交易,基於它們的費用劃分優先順序的演算法,在第8章有詳細解釋。

5.4.4 把交易費加到交易中

交易的資料結構沒有交易費的欄位。相反地,交易費通過所有輸入的總和,以及所有輸出的總和之間的差來表示。從所有輸入中扣掉所有輸出之後的多餘的量會被礦工收集走。

交易費被作為輸入減輸出的餘量:

交易費 = 求和(所有輸入) - 求和(所有輸出)

對於交易來說,這是一個很讓人摸不著頭腦的元素,但又是很重要的問題。因為如果你要構造你自己的交易,你必須確認你沒有疏忽地包含了一筆少於輸入的、量非常大的費用。這意味著你必須計算所有的輸入,如果必要的話進行找零,不然的話,結果就是你給了礦工一筆可觀的勞動費!

舉例來說,如果你消耗了一個20比特幣的UTXO來完成1比特幣的付款,你必須包含一筆19比特幣的找零回到你的錢包。否則,那剩下的19比特幣會被當作交易費,並且會被挖出你的交易到一個區塊中的礦工收走。儘管你會受到高優先順序的處理,並且讓一個礦工喜出望外,但這很可能不是你想要的。


如果你忘記了在手動構造的交易中增加找零的輸出,系統會把找零當作交易費來處理。“不用找了!”也許不是你想要的結果。

讓我們來看看在實際中它如何工作,重溫一下Alice在咖啡店的交易。Alice想為咖啡支付0.015比特幣。為了確保這筆交易能立即被處理,Alice想支付一筆交易費,比如說0.001。這意味著總交易成本會變成0.016。因此她的錢包需要湊齊0.016或更多的UTXO。如果需要,還要加上找零。我們假設他的錢包有一個0.2比特幣的UTXO可用。他的錢包就會消耗掉這個UTXO,創造一個新的0.015的輸出給Bob的咖啡店,另一個0.184比特幣的輸出作為找零回到Alice擁有的錢包,並留下未分配的0.001比特幣內含在交易中。

現在讓我們換個例子。Eugenia,我們在菲律賓的兒童募捐專案主管,完成了一次為孩子購買教材的籌款活動。她在世界範圍內接收到了好幾千個小數額的捐款,總額是50比特幣。所以她的錢包塞滿了非常小的UTXO。現在她想用比特幣從本地的一家出版商購買幾百本的教材。

現在Eugenia的錢包應用想要構造一個單筆大額付款交易,它必須從可用的、由很多小數額構成的大的UTXO集合中尋求錢幣來源。這意味著交易的結果是從上百個小數額的UTXO中作為輸入,但只有一個輸出用來付給出版商。輸入數量這麼巨大的交易會比一千位元組要大,也許總尺寸會達到兩至三千位元組。結果是它需要更高的交易費來滿足0.0001比特幣的網路費。

Eugenia的錢包應用會通過測量交易的大小,乘以每千位元組需要的交易費,來計算適當的交易費。很多錢包會通過多付交易費的方式來確保大交易被立即處理。高交易費不是因為Eugenia付的錢很多,而是因為她的交易很複雜並且尺寸很大——交易費是與參加交易的比特幣值無關的。

5.5 交易鏈條和孤立交易

正如我們之前所看到的那樣,交易形成一條鏈,這條鏈的形式是一筆交易消耗了先前的交易(父交易)的輸出,併為隨後的交易(子交易)創造了輸出。有的時候組成整個鏈條的所有交易依賴於他們自己——比如父交易、子交易和孫交易——而他們又被同時創造出來,來滿足複雜交易的工作流程。這需要在一個交易的父交易被簽名之前,有一個合法的子交易被簽名。舉個例子,這是CoinJoin交易使用的一項技術,這項技術可以讓多方同時加入交易,從而保護他們的隱私。

當一條交易鏈被整個網路傳送時,他們並不能總是按照相同的順序到達目的地。有時,子交易在父交易之前到達。在這種情況下,節點會首先收到一個子交易,而不能找到他參考的父交易。節點不會立即拋棄這個子交易,而是放到一個臨時池中,並等著接收它的父交易,與此同時廣播這個子交易給其他節點。沒有父交易的交易池被稱作孤立交易池。一旦接收到了父交易,所有與這個父交易建立的UTXO有關的孤塊會從池中釋放出來,遞迴地重新驗證,然後整條交易鏈就會被交易池包括進去,並等待著被區塊所挖走。交易鏈可以是任意長度並且可以被任意數量的批次同時傳走。在孤立池中保留孤塊的機制保證了其他合法的交易不會只是因為父交易被耽誤了而被拋棄,並且無論接收順序,最終整個鏈會以正確的順序重新構造出來。

記憶體中儲存的孤立交易數量是有限制的,這是為了防止針對比特幣節點的拒絕服務攻擊(DoS)。這個限制被定義在比特幣涉及到的客戶端的原始碼中的MAX_ORPHAN_TRANSACTIONS。如果池中的孤立交易數量達到了MAX_ORPHAN_TRANSACTIONS,一個或多個的、被隨機選出的孤立交易會被池拋棄,直到池的大小回到限制以內。

5.6 比特幣交易指令碼和指令碼語言

比特幣客戶端通過執行一個用類Forth指令碼語言編寫的指令碼驗證比特幣交易。鎖定指令碼被寫入UTXO,同時它往往包含一個用同種指令碼語言編寫的簽名。當一筆比特幣交易被驗證時,每一個輸入值中的解鎖指令碼被與其對應的鎖定指令碼同時(互不干擾地)執行,從而檢視這筆交易是否滿足使用條件。

如今,大多數經比特幣網路處理的交易是以“Alice付給Bob”的形式存在的。同時,它們是以一種稱為“P2PKH”(Pay-to-Public-Key-Hash)指令碼為基礎的。然而,通過使用指令碼來鎖定輸出和解鎖輸入意味著通過使用程式語言,比特幣交易可以包含無限數量的條件。當然,比特幣交易並不限於“Alice付給Bob” 的形式和模式。

這只是這個指令碼語言可以表達的可能性的冰山一角。在這一節,我們將會全面展示比特幣交易指令碼語言的各個組成部分;同時,我們也會演示如何使用它去表達複雜的使用條件以及解鎖指令碼如何去滿足這些花費條件。


比特幣交易驗證並不基於一個不變的模式,而是通過執行指令碼語言來實現。這種語言可以表達出多到數不盡的條件變種。這也是比特幣作為一種“可程式設計的貨幣”所擁有的權力。

5.6.1 指令碼建立(鎖定與解鎖)

比特幣的交易驗證引擎依賴於兩類指令碼來驗證比特幣交易:一個鎖定指令碼和一個解鎖指令碼。

鎖定指令碼是一個放在一個輸出值上的“障礙”,同時它明確了今後花費這筆輸出的條件。由於鎖定指令碼往往含有一個公鑰(即比特幣地址),在歷史上它曾被稱作一個指令碼公鑰程式碼。由於認識到這種指令碼技術存在著更為寬泛的可能性,在本書中,我們將它稱為一個“鎖定指令碼”。在大多數比特幣應用原始碼中,指令碼公鑰程式碼便是我們所說的鎖定指令碼。

解鎖指令碼是一個“解決”或滿足被鎖定指令碼在一個輸出上設定的花費條件的指令碼,同時它將允許輸出被消費。解鎖指令碼是每一筆比特幣交易輸出的一部分,而且往往含有一個被使用者的比特幣錢包(通過使用者的私鑰)生成的數字簽名。由於解鎖指令碼常常包含一個數字簽名,因此它曾被稱作ScriptSig。在大多數比特幣應用的原始碼中,ScriptSig便是我們所說的解鎖指令碼。考慮到更寬泛的鎖定指令碼要求,在本書中,我們將它稱為“解鎖指令碼”。但並非所有解鎖指令碼都一定會包含簽名。

每一個比特幣客戶端會通過同時執行鎖定和解鎖指令碼來驗證一筆交易。對於比特幣交易中的每一個輸入,驗證軟體會先檢索輸入所指向的UTXO。這個UTXO包含一個定義了花費條件的鎖定指令碼。接下來,驗證軟體會讀取試圖花費這個UTXO的輸入中所包含的解鎖指令碼,並執行這兩個指令碼。

在先前的比特幣客戶端中,解鎖和鎖定指令碼是以連鎖的形式存在的,並且是被依次執行的。出於安全因素考慮,在2010年比特幣開發者們修改了這個特性——因為存在“允許異常解鎖指令碼推送資料入棧並且汙染鎖定指令碼”的漏洞。在當今的比特幣世界中,這兩個指令碼是隨著堆疊的傳遞被分別執行的,後續將會詳細介紹。

首先,使用堆疊執行引擎執行解鎖指令碼。如果解鎖指令碼在執行過程中未報錯(沒有懸空操作符),主堆疊(非其它堆疊)將被複制,然後指令碼將被執行。如果採用從解鎖指令碼處複製而來的資料執行鎖定指令碼的結果為真,那麼解鎖指令碼就成功地滿足了鎖定指令碼所設定的條件,因而,該輸入是一個能使用該UTXO的有效授權。如果在執行完組合指令碼後的結果不是真,那麼輸入就不是有效的,因為它並未能滿足UTXO中所設定的使用該筆資金的條件。注意,UTXO是永久性地記錄在區塊鏈中的,因此它不會因一筆新交易所發起的無效嘗試而變化或受影響。只有一筆有效的能準確滿足UTXO條件的交易才會導致UTXO被標記為“已使用”,然後從有效的(未使用)UTXO集中所移除。

圖5-1是最為常見型別的比特幣交易(向公鑰雜湊進行一筆支付)的解鎖和鎖定指令碼樣本,該樣本展示了在指令碼驗證之前將解鎖指令碼和鎖定指令碼串聯而成的組合指令碼。


圖5-1

5.6.2 指令碼語言

比特幣交易指令碼語言,也稱為指令碼,是一種基於逆波蘭表示法的基於堆疊的執行語言。如果這讓您聽起來似乎在胡言亂語,很有可能是您沒學習過1960年的程式語言的緣故。指令碼是一種非常簡單的語言,這種語言被設計為能在有限的硬體上執行,這些硬體類似簡單的嵌入式裝置,如手持計算器。它僅需最少的處理即可,而且不能做許多現代程式語言可以做的事情。當涉及可程式設計的錢時,這是它的一個基於深思熟慮的安全特性。

比特幣指令碼語言被稱為基於棧語言,因為它使用的資料結構被稱為棧。棧是一個非常簡單的資料結構,它可以被理解成為一堆卡片。棧允許兩類操作:入棧和出棧。入棧是在棧頂部增加一個專案,出棧則是從棧頂部移除一個專案。

指令碼語言通過從左至右地處理每個專案的方式執行指令碼。數字(常數)被推送至堆疊,操作符向堆疊推送(或移除)一個或多個引數,對它們進行處理,甚至可能會向堆疊推送一個結果。例如,OP_ADD將從堆疊移除兩個專案,將二者相加,然後再將二者相加之和推送到堆疊。

條件操作符評估一項條件,產生一個真或假的結果。例如,OP_EQUAL從堆疊移除兩個專案,假如二者相等則推送真(表示為1),假如二者不等則推送為假(表示為0)。比特幣交易指令碼常含條件操作符,當一筆交易有效時,就會產生真的結果。

相關推薦

學習筆記——————5 交易

5.1 簡介比特幣交易是比特幣系統中最重要的部分。根據比特幣系統的設計原理,系統中任何其他的部分都是為了確保比特幣交易可以被生成、能在比特幣網路中得以傳播和通過驗證,並最終新增入全球比特幣交易總賬簿(比特幣區塊鏈)。比特幣交易的本質是資料結構,這些資料結構中含有比特幣交易參與

學習筆記——————8挖礦與共識

8.1 簡介挖礦是增加比特幣貨幣供應的一個過程。挖礦同時還保護著比特幣系統的安全,防止欺詐交易,避免“雙重支付”,“雙重支付”是指多次花費同一筆比特幣。礦工們通過為比特幣網路提供算力來換取獲得比特幣獎勵的機會。礦工們驗證每筆新的交易並把它們記錄在總帳簿上。每10分鐘就會有一個

學習筆記——————1簡介

1.1 什麼是比特幣比特幣是由一系列概念和技術作為基礎構建的數字貨幣生態系統。狹義的“比特幣”代表系統中的貨幣單位,用於儲存和傳輸價值。使用者主要通過網際網路使用比特幣系統,當然其他網路也可以使用。比特幣協議以各種開源軟體的形式實現,這些軟體可以在膝上型電腦、智慧手機等多種裝

精通學習(一)

nbsp 價值 數字 傳播 實現 筆記 互聯網 發生 CA 一、比特幣基本概念: 1. 比特幣概念: 廣義:比特幣是由一系列概念和技術作為基礎構建的數字貨幣生態系統。 狹義:代表數字貨幣生態系統中的貨幣單位,用於儲存和傳

程式碼分析5 挖礦程式碼分析

本文描述礦工處理執行緒,通過本文學習,可以瞭解礦工挖礦的大致流程。主要包含挖礦費用交易的產生、當前交易池的打包處理,工作量證明等相關內容。流程圖(參考網路)如下所示:。 礦工處理函式1.void ThreadBitcoinMiner(void* parg)2.{ vfThreadRunning[3]

代碼分析7 交易校驗

數字 key hash 序列號 才會 第一個 100萬 pub 匹配 每一個收到交易,比特幣節點都驗證該交易,有效的交易將被傳遞到各個附近節點,這將確保只有有效的交易才會在網絡中傳播, 而無效的交易將會在第一個節點處就被廢棄。校驗選項列表:每一個節點在校驗每一筆交易時,都需

使用PHP和樹莓派開發一個和以太坊交易機器人

我最近得到了Raspberry Pi Zero Wifi,我告訴你這個東西是改變遊戲規則的。我之前使用過RasPis,但由於該裝置的佔地面積小得多,耗電少,價格便宜且無線上網,因此非常適合低端或物聯網專案。 注:目前我已經擴充套件了機器人以便能夠交易以太坊! 我希望它能夠在不必太多關注的情況下做事,而我想到

精通(第六章)【交易

6.1 簡介 比特幣交易是比特幣系統中最重要的部分。根據比特幣系統的設計原理,系統中任何其他的部分都是為了確保比特幣交易可以被生成、能在比特幣網路中得以傳播和通過驗證,並最終新增入全球比特幣交易總賬簿(比特幣區塊鏈)。比特幣交易的本質是資料結構,這些資料結構中含

刷單機器人對衝交易軟體開發,量化交易平臺開發

什麼是量化交易:大量程式化,是指以先進的數學模型替代人為的主觀判斷,在能帶來超額收益的“大概率”事件中,利用演算法模型做出高頻理性的策略,極大地減少了玩家情緒波動的影響,避免在市場極度狂熱或悲觀的情況下作出非理性的決策。對衝即同時進行兩筆行情相關向相反、數量相當、盈虧相抵的交易。行情相關是指影響兩種商品價格行

學習-Transaction的locktime屬性

Locktime, also known as nLockTime from the variable name used in the reference client, defines the earliest time that a transaction is valid and can be rel

go實現橢圓曲線加解密簽名驗證演算法(go ecdsa庫的運用),及生成地址過程講解base58實現

go實現橢圓曲線加解密、簽名驗證演算法(go ecdsa庫的運用),及生成比特幣地址過程講解、BASE58實現 前言 本文主要講解使用Go的ecdsa庫實現橢圓曲線加解密、簽名、驗證演算法,同時通過公鑰生成比特幣地址,具體程式碼邏輯參考bitcoin0

學習之-P2P網路

比特幣的網路採用了基於國際網際網路(Internet)的P2P網路架構。英文是peer to peer,所以也叫對等網路。顧名思義也就是網路中的每臺計算機是對等的,各個節點共同提供網路服務,不存在任何“特殊”節點。在 P2P 網路中不存在任何服務端(server)、中央化的服務、以及層級結構。這也是比特幣網路

歷史性的八筆交易

比特幣歷史性的八筆交易 比特幣交易並沒有什麼特別之處,每天BTC和BCH網路上都會有30萬筆這樣的交易。但有時候,一筆普通的交易也會具有歷史性意義。這些比特幣交易可以在任何區塊鏈瀏覽器中檢視,並且被永遠留在公開分類賬裡面。在礦工眼中所有的比特幣交易都是平等的,只要附加了足夠的費用,無論傳

區塊鏈(1)—— 中的區塊賬戶驗證和記賬

上一篇說到比特幣是一種去中心化的電子現金系統。去中心化說起來似乎挺簡單,但是不用細想就會發現很多問題:賬本儲存在每個節點中,如何保證每個節點中的資料一致,或者說如何防止某些節點的賬本被惡意篡改而影響到整個網路的交易? 如果說交易的驗證由各個節點完成,那麼如何在不把密碼洩露給其

的產生原理運作方式特點區塊鏈等

摘要:要近期比特幣已經成為主流討論的熱門話題,自8月12日突破4000美元以來,比特幣的價格達到了前所未有的高點。根據CoinDesk比特幣價格指數,比特幣的價格今年迄今已上漲逾300%,總市

bitcoin-cli轉賬與交易的api使用總結

需要使用到3個api,分別是 createrawtransaction(建立交易),signrawtransaction (簽名交易),sendrawtransaction(廣播交易), 2.1命令格式: createrawtransaction [{“txid”:”id”,”vout”:n},…] {“

3區塊鏈之的私鑰公鑰地址

我們之前說到比特幣具有很強的安全性和匿名性,這兩點的基礎就在於比特幣的私鑰、公鑰和地址。 私鑰是一串隨機數字,由256位 0 和 1 組成,通常用 16 進製表示,一共有64位。 公鑰則是由私鑰通過橢圓曲線演算法生成的,而此過程是不可逆,也即無法從公鑰推出私

2.7 與區塊鏈:交易確認

Reward(獎勵) 有一件前面的章節中跳過了一個小細節,挖礦獎勵。現在我們準備實現這個。  這個獎勵也就是coinbase交易。當一個節點開始挖新的區塊時,它會把佇列中的交易並準備好coinbase交易放到區塊中。這筆coinbase交易也僅僅是一個包含了礦工的公鑰has

學習-modular inverse

問題:A mod C 的inverse 的值是多少? (What is the value of the inverse of A mod C? )  答案:當B的值滿足,A*B mod C = 1 時, B 即為A mod C 的inverse 的值。 ( If B sa

學習(1)難度調整

難度值(difficulty)是礦工們在挖礦時候的重要參考指標,它決定了礦工大約需要經過多少次雜湊運算才能產生一個合法的區塊。比特幣的區塊大約每10分鐘生成一個,如果要在不同的全網算力條件下,新區塊的產生保持都基本這個速率,難度值必須根據全網算力的變化進行調整。簡單地說,難度