天天看點

《區塊鍊開發指南》一一1.1 交易和交易鍊

本節書摘來自華章計算機《區塊鍊開發指南》一書中的第1章,第1.1節,作者:申屠青春 主編 宋 波 張 鵬 汪曉明 季宙棟 左川民 編著更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視。

交易是簽過名的資料結構,該資料結構會在區塊鍊網絡中廣播,并被收集到區塊中。它會引用以前的交易,從該交易中發送特定數量的比特币到一個或多個公鑰中(即比特币位址),并且交易未被加密(比特币體系中沒有加密任何資料)。多個交易可組成一個區塊(block),這些區塊同樣也會在區塊鍊網絡中傳播,一個區塊會引用上一個區塊,簡而言之,區塊鍊就是由區塊(block)用某種方式組織起來的鍊條(chain)。區塊鍊包括成千上萬個區塊,而一個區塊内又包含一個或多個交易,上下關聯的交易組成了一個交易鍊,一個交易鍊内部可能又包含了多個交易,下面的章節将會對這些知識點進行詳細解釋。

1.1.1 比特币位址

比特币位址是一個由數字和字母組成的字元串,可以與任何想給你比特币的人分享。由公鑰(一個同樣由數字和字母組成的字元串)生成的比特币位址以數字“1”開頭。下面是一個比特币位址的例子:

1j7mdg5rbqyuhenydx39wvwk7fslpeoxzy

在交易中,比特币位址通常是以收款方的形式出現。如果把比特币交易比作一張支票,那麼比特币位址就是收款人,也就是我們要寫入“收款人”一欄的内容。一張支票的收款人可能是某個銀行賬戶,也可能是某個公司、機構,甚至是現金支票。支票不需要指定一個特定的賬戶,而是可以用一個普通的名字作為收款人,這使得它成為一種相當靈活的支付工具。與此類似,比特币位址的使用也使比特币交易變得很靈活。比特币位址可以代表一對公鑰和私鑰的所有者,也可以代表其他東西。

比特币位址是由公鑰經過單向的hash函數生成的。使用者通常所見到的比特币位址是經過“base58check”編碼的,這種編碼使用了58個字元(一種base58數字系統)和校驗碼,提高了可讀性、避免了歧義,并有效地防止了在位址轉錄和輸入中産生錯誤。base58check編碼也被用于比特币的其他地方,例如私鑰、加密的密鑰和腳本hash中,用來提高可讀性和錄入的正确性。圖1-1描述了如何從公鑰生成比特币位址。

1.1.2 交易的本質

交易實質上就是包含一組輸入清單和輸出清單的資料結構,也可稱之為轉賬記錄,這其中就包括了交易金額、來源和收款人等資訊,表1-1就是一個比特币交易的資料格式。

《區塊鍊開發指南》一一1.1 交易和交易鍊
《區塊鍊開發指南》一一1.1 交易和交易鍊

圖1-1 比特币位址生成流程

下面以一個具體的例子來說明一個區塊鍊上的交易構成。假設有一個帶有一個交易及一個輸出的交易a,其中的輸入清單和輸出清單如下所示:

上文表示,交易a的輸入0從交易f5d8ee39a430901c91a5917b9f2dc19d6d1a0e9cea205b009ca73dd04470b9a6的0号輸出中導入了50個比特币,然後該輸出發送50個比特币到一個比特币位址的公鑰hash值(404371705fa9bd789a2fcd52d2c580b65d35549d,該公鑰hash值是十六進制表示,而非正常的base58表示)。

如果接收者想花掉這筆錢,那麼他首先得建立自己的交易b,再引用該交易a的0号輸出作為交易b的輸入。

1.1.3 輸入和輸出

輸入是對其他交易輸出的引用,一個交易中通常列有多個輸入。所有被引用的輸出值相加,得出的總和值會在該交易a的輸出中用到。previous tx是以前交易的hash值,index是被引用交易的特定輸出号,scriptsig是一個腳本的前一半(腳本将在後文中詳細讨論)。

腳本包含兩個部分,一個簽名和一個公鑰,公鑰屬于交易輸出的收款人,并且表明交易建立者允許收款人獲得的輸出金額;另一個部分是ecdsa簽名,是通過對交易的hash值進行ecdsa簽名而得到的。簽名和公鑰一起,證明原位址的真正所有者建立了該支付交易。

輸出中包含了發送比特币的指令,金額(value)是以聰(satoshi, 1btc = 100?000?000聰)為機關的數值。scriptpubkey是腳本的另一半(這點将在後文中詳細讨論),可以有多個輸出,它們共享了輸入金額。一個交易中的每一個輸出都隻能被後來的交易當成輸入引用一次。如果你不想丢币,那就需要把所有輸入值的總和值發送到一個輸出位址。如果輸入是50btc,但你僅想發送25btc,那麼比特币将建立2個25btc的輸出:一個發往目标位址,另一個則回到你的位址(稱之為“找零”,詳見1.1.5節)。在交易過程中,會産生一筆交易費,作為交易費支付的任何比特币都不能被贖回,生成這個區塊的礦工将獲得這筆交易費。

為了驗證某個交易的輸入已經被授權,可以收集被引用的輸出中的所有金額。比特币體系使用了一個類似于forth的腳本系統,其目的是驗證從某位址發出的比特币是否真正屬于該位址的擁有人,輸入的scriptsig和被引用的輸出scriptpubkey會按順序運作。如果scriptpubkey傳回真,則輸入被授權,證明是位址擁有人發出了比特币。通過腳本系統,發送者可以建立非常複雜的發送條件,人們為了收到金額,首先必須滿足這些條件。舉個例子,可以建立一個能被任何人贖回而無需授權的輸出,也可以建立一個需要10個不同簽名的輸入,或者無需公鑰僅由密碼贖回的輸出。

1.1.4 交易類型

根據目标位址的不同,可以把交易分為如下幾種類型。

(1)支付到公鑰hash

scriptpubkey: op_dup op_hash160 op_equalverify op_checksig

scriptsig:

一個比特币位址隻是一個hash值,因而發送者無法在scriptpubkey中提供完整的公鑰,當要贖回比特币時,接收者需要同時提供簽名scriptsig和公鑰scriptpubkey,腳本系統會驗證公鑰的hash值與scriptpubkey中的hash值是否比對,同時還會檢查公鑰和簽名是否比對。檢查過程見4.2.5節。

(2)支付到腳本hash

該類交易非常有意義,未來應該會在某些場合頻繁使用。該類交易的接受位址不是通常意義上的位址,而是一個多簽位址,以3開頭。比如,三對公鑰對可以生成一個多簽位址。需要在生成過程中指定n of 3中的n,n的範圍是[1, 3],若n = 1,則僅需要一個私鑰簽名即可花費該位址的币,若n = 3,則需要三把私鑰依次簽名才可以。

位址以3開頭,可以實作多方管理資産,極大地提高安全性,也可以輕松實作基于比特币原生的三方交易擔保支付。一個m-of-n的模式如下:

m {pubkey}...{pubkey} n op_checkmultisig

其中,m和n需要滿足:1 ≤ n ≤ 20,m ≤ n。

m和n可以是1 of 1、1 of 2、2 of 3等組合,通常選擇n = 3。

1 of 3,最大程度私鑰備援。防丢私鑰損失,3把私鑰中任意一把即可簽名發币,即使丢失2把也可以保障不受損失。

2 of 3,提高私鑰備援度的同時解決單點信任問題。3把私鑰中的任意2把私鑰可簽名發币,對于三方不完全信任的情形,即中介交易,非常适用。

3 of 3,最大程度解決資金信任問題,無私鑰備援。必須3把私鑰全部簽名才能發币,适用于多方共同管理的重要資産,但是任何一方遺失私鑰均會造成嚴重損失。

多簽位址的交易構造、簽名、發送過程與普通交易類似。

(3)挖礦交易

挖礦(coinbase)交易用于憑空産生比特币。挖礦交易隻有一個輸入,該輸入有一個“coinbase”參數,沒有scriptsig,“coinbase”中的資料可以是任意内容,它不會被使用。比特币把壓縮的目前目标hash值和任意精确度的“extranonce”都存儲在這兒,區塊頭中的nonce每次一溢出,它們就會增長。extranonce有助于擴大工作量證明函數的範圍,礦工很容易修改nonce(4位元組)、時間戳和extranonce(2~100位元組)。

挖礦交易的輸出金額在一段時間内是固定值,初始是50個比特币,每21萬個區塊後減半,目前已經經曆了兩次減半,因而是12.5個比特币。輸出位址可以是任何位址,一般是礦工或礦池的比特币位址。

nonce溢出是指在對一個塊進行散列時,nonce從0開始,每計算一次hash都要增長一次,因而有可能會出現超過數值範圍的情況,這時,extranonce就要相應增長以存儲nonce。

1.1.5 找零位址

在實際的區塊鍊交易中,假設a擁有一個比特币位址,裡面包含着還沒有花費過的10個比特币。b也有一個比特币位址,裡面一分錢也沒有。當a想向b支付10個比特币時,a位址裡的未花費輸出變為零,而b的則會變為10 btc。如果a想支付的金額與所擁有的相同,自然不會存在需要找零錢的問題。不過當手頭的金額比要支付的大時,找零自然也是天經地義的事情。

假設a的位址上有35個比特币(如圖1-2所示),當a想向b支付8個比特币時,如圖1-2所示,隻需要使用包含着20個比特币的那一筆未消費支出,并設定好要支援的金額即可,剩下的12個比特币則會傳回給a,以便a在将來可以繼續使用。

《區塊鍊開發指南》一一1.1 交易和交易鍊

圖1-2 找零示意圖

這樣就有了一個找零機制,實際上,比特币在交易時會把消費時所用的位址(消費位址)的餘額設定為零。當需要支付的金額小于可用餘額時,在交易資訊中必須告訴比特币網絡零錢将要被發送至哪個位址,即“找零位址”。找零位址可能是也可能不是原先的發送位址。除此之外,發送位址所留下的剩餘款項将由網絡作為交易費支付給礦工。在上面的例子裡,a可以選擇将找回的零錢發送到一個新建立的找零位址上,或者将原先發送的位址設定為找零位址,并将零錢傳回。雖然将發送位址作為找零位址對a而言是友善了管理,不過這也可能會造成a的隐私性降低,在一定程度上還可能會影響到b的匿名性。

根據設計,每一筆比特币交易将在一個稱為“區塊鍊”的全球性的公共總賬上永久可見,這就意味着任何人随時都可以在上面進行跟蹤查詢。通過将某個比特币位址與其使用者關聯起來,好事者都可以據此繪制關于這個人與他人之間的資金轉移的關系圖。但如果是将找回的零錢發送至一個新建立的位址,那麼就可以讓這種追蹤變得更加困難。

要了解這一點,可以參考圖1-3。假設從位址a發送比特币到位址b後,零錢傳回位址為a,則區塊鍊會揭示位址a向位址b支付了一筆錢。同樣的道理,如果有兩個或兩個以上位址參與其中,任何涉及這個接收零錢的找零位址都會揭示a作為支付方的交易。假如某個控制着的任何接收位址或付款位址的人其身份是衆所周知的,那麼其他有過交易往來的各方的身份也有可能被推斷出來。

現在想象一下,位址a發起付款到位址b,但此時将找零位址更改為新生成的位址c,如圖1-4所示。如果沒有進一步的資訊,那麼其他人所能知道的,隻是有一個交易拆分了位址a的餘額至位址b和c。而位址b或c的主人可能是也可能不是a。由于新位址c的加入,讓整個交易的真相變得更加撲朔離迷:哪一個位址代表着被支付方,哪一個位址代表着找回的零錢呢?

當所有各方都将零錢發送至新建立的位址時,要想将個人身份與位址相關聯,就必須收集更多的資訊,并耗費更多的資源。

繼續閱讀