肖臻老師區塊鏈公開課筆記

前段時間,區塊鏈大火,出現了很多種基於區塊鏈技術的政務應用。之前通過零散的網頁信息和講座,自我感覺理解了block chain原理,當看到各種區塊鏈技術廣泛應用時,自己以技術理解,反而對之不屑。當然,也懷疑自己還沒有理解了區塊鏈。

帶着這種好奇,在B站上找區塊鏈的課程,找到了北大肖臻老師的公開課。這門課是肖臻老師2018年北大暑期課程,課程內容包括比特幣和以太坊2部分。以肖老師真實課堂上的錄像爲主,補充了後期PPT,大約20個小時。肖老師的比特幣部分講的比較細,以太坊就粗一些。想要深入學習區塊鏈開發,還要自己學習,但充分體會到老師給出一個大綱,能給出你一個知識體系非常重要。在課程留出了很多空白,但這些空白就是驅動自主學習非常好的動力!

肖老師講課沒有配套講義,需要自己整理筆記。如果不整理好筆記,不能總是翻視頻回憶知識點吧。課堂中主要講設計思想,這些經過實踐檢驗的區塊鏈技術,凝結了偉大的設計思想。筆記中,整理了自己的理解,爲比特幣腳本部分畫了一些圖來說明執行流程。

如果你對:哈希鏈表、區塊打包、挖礦無記憶性、比特幣腳本這些問題還有疑惑,可以看看我的筆記,並留言一起交流。

 

一、 簡介

1.1 教材

教材和參考資料如下:

  1. BitCoin and CryptoCurrency Technologies A comprehensive introduction (2016)
  2. 以太坊白皮書、黃皮書、源代碼
  3. Solidity 文檔

1.2 主要內容

比特幣:

  1. 密碼學基礎
  2. 比特幣的數據結構
  3. 共識協議和系統實現
  4. 挖礦算法和難度調整
  5. 比特幣腳本
  6. 軟分叉和硬分叉
  7. 匿名和隱私保護

以太坊:

  1. 概述:基於賬戶的分佈式賬戶
  2. 數據結構:狀態樹、交易樹、收據樹
  3. GHOST協議
  4. 挖礦:memory-hard mining puzzle
  5. 挖礦難度調整
  6. 權益證明 casper the Friend Finality Gadget(FFG)
  7. 智能合約

二、 BTC密碼學原理

2.1 哈希

加密貨幣特性:crypto-currency 本身並不加密,轉賬地址是公開。主要使用了哈希函數,哈希函數特性:Cryptographic hash function ,collision resistance,抗碰撞性。

x=y 那麼 Hash(x)=Hash(y);而且 Hash(x)≠Hash(y),那麼x≠y

人爲製造哈希collision沒有好的方法,只能採用窮舉法破解,brute-force。d在比特幣系統中,採用SHA-256算法。輸出空間爲2^256。

哈希函數的作用:生成消息摘要digest。在實際生活中,以網盤上傳文件爲例,文件上傳前計算文件的Hash值,下載保存文件後,再次計算文件的Hash值,如果2個Hash值不一致,文件就是被篡改了。如果2個Hash值一致,那麼保存在雲盤上的文件是沒有被篡改過的。(雲廠商爲什麼要篡改文件,雲廠商本身的原因造成文件損壞,用戶沒有察覺這個問題,通過校驗Hash值的方式可以發現)。

哈希函數作用二:信息隱藏。舉例爲,我要預測股票,將股票預測文本的摘要hash公佈出去,但是股票預測這段文本M沒有公佈。當股票結果被證實了(經過一段時間),我再將股票預測文本M公佈,所有人都可以用Hash算法驗證M摘要信息hash2,如果hash2=hash,那麼可以證明我之前公佈文本M。

信息隱藏必須滿足條件,輸入的樣本空間必須大。否則,惡意攻擊者會窮舉輸入,找到產生摘要的原文。例如,股票的個數比較少,那麼可以添加隨機數,計算H(X || nonce)並公佈,公佈原文的時候要一併公佈隨機數nonce。可能有人會懷疑,我通過修改X和nonce,僞造了摘要信息,但是哈希函數的抗碰撞性,僞造出這個摘要值是非常困難的。

2.2 工作量證明

在比特幣中要求,合法的區塊必須滿足:

H(block header)≤target

在區塊頭(block header)中有一個域nonce,窮舉計算nonce,計算block header哈希值小於target,確定一個合法區塊。

區塊鏈的工作原理,記賬節點(礦工)收集網絡上廣播的交易(tx),維護一個交易集合,將若干筆交易打包,計算交易列表hash,放在block header中,窮舉nonce域,使H(block header)≤target。

由於Hash函數的puzzle friendly特性,只能使用窮舉算法。挖礦的主要工作就是通過窮舉計算,找到符合條件的區塊頭。礦工找到符合條件塊頭,就獲得了記賬權,獲得出塊獎勵和交易費,礦工要把這個區塊信息發佈到網絡上,以便其他礦工能夠收到這個區塊信息。

2.3 賬戶信息

在比特幣中,用戶可以自己創建一個公私鑰對,公鑰就作爲用戶的賬戶信息。公私鑰體系又稱爲非對稱密碼體系,一對密碼分爲(public key,private key),私鑰保密,公鑰公開。利用公私鑰實現信息的保密通信和數字簽名。

Alice想要給Bob發送信息,Alice在公開場景下獲取了Bob的公鑰,Bob的私鑰自己保密。那麼Alice用Bob的公鑰加密信息發送給Bob,Bob接收到信息後,用Bob自己私鑰解密。加密後的密文可以在不安全的信道上傳輸,沒有Bob的私鑰,無法解密密文。

數字簽名可以用來實現信息的真實性和抗抵賴性。Alice要向Bob提供一版word版報價單,Bob要求Alice提供報價單的真實性證明,Alice可以採用Hash算法計算文件的摘要,並用Alice自己的私鑰對摘要加密,加密後的結果就是數字簽名,Alice把原始word文檔和數字簽名一起發給Bob。Bob收到word文件時,可以計算word摘要,並用Alice的公鑰解密數字簽名,如果收到的word文檔摘要和摘要數字簽名解密後的結果一致,證明了報價單在傳遞過程中沒有被篡改,也證明了確實是Alice認可的文檔。

在BTC中,用戶可以任意生成公私鑰,將公鑰公佈作爲自己的賬號地址,私鑰作爲賬戶所屬權證明。實現轉賬時,發起向某個公鑰地址轉賬的交易(tx),那麼這個公鑰對應的賬號就獲得了這筆交易的金額。

在2.2節可以看到比特幣的區塊中記錄的都是一筆一筆交易(tx),而發起交易的節點並不是直接將交易寫到區塊鏈上,而是發佈到網絡上,讓礦工節點接收。礦工節點通過挖礦獲得記賬權,發佈打包交易的區塊。

這裏有一個問題,如果是用戶自己產生公私鑰,而私鑰能夠代表一個人身份,如果產生的公私鑰重複,怎麼辦?比特幣採用的公鑰算法,公鑰空間很大,這樣即使用戶自己產生公私鑰,發生碰撞的概率也很小。同樣是這個原因,通過窮舉公私鑰對比特幣賬戶進行攻擊,也是不能實現的。但是,用戶在生成公私鑰時,應採用優質的隨機源。如果隨機源用的不好,一次簽名也可以泄露私鑰。

三、 BTC中的數據結構

3.1 哈希指針

區塊鏈是利用指針將區塊連接起來,後一個指向前一個,並hash指針代替傳統指針。

採用Hash指針替代傳統指針有2個特點:

(1)計算機中常用指針是內存中的地址,指向一塊內存空間。比特幣中區塊鏈信息不可能全部保存在內存中,要在硬盤存儲中實現指針,區塊鏈利用用了(key,value)型存儲數據庫,區塊頭的hash值作爲key,整個區塊信息作爲value進行存儲。查找當前區塊的內容,可以計算區塊頭的hash值,並在數據庫中存儲。區塊頭中保存了上一個區塊哈希值,這個hash值就是hash指針,也是上一個區塊的key值。

(2)通過hash指針實現區塊鏈的防篡改,後面的區塊保存了前一個區塊Hash值(hashPreBlock),並用這個值計算自己的hash。如果想要篡改歷史中交易信息,那麼塊頭的hash值必然改變(如何產生影響,見3.2)。想要使修改的交易合法,就必須修改下一區塊hashPreBlock,如此下一個區塊又要修改下下一個區塊的塊頭。這種修改區塊鏈內容的方法,在實際過程中有很大的難度,修改一個區塊,和挖礦獲得記賬的難度一樣,從效率上是趕不上區塊鏈中合法礦工的挖礦速度,因此很難讓其他礦工接受。

3.2 區塊體交易結構

區塊body中保存了交易列表,計算交易列表的hash,保存在區塊header中。交易的組織採用了一個數據結構Merkle tree默克爾樹,結構如下圖所示:

交易由下至上,組織成一棵二叉樹,上層生成下層2個節點的hash值,最終生成一個哈希值Merkle root,保存在block header中。

如果惡意節點修改了交易(tx)中內容,那麼Merkle tree就會改變,最終反映在Merkle root變化上,那麼block header就會發生變化。採用這種方法保證了區塊鏈中交易不可篡改性。

3.3 Merkle proof

區塊鏈中包含2種節點,全節點和輕節點。全節點是保存完整區塊鏈,參與挖礦記賬的節點。在比特幣網絡中,大部分屬於輕節點,輕節點不保存完整區塊鏈,只保存最近一些節點的塊頭。常見的比特幣手機錢包,就屬於輕節點。

輕節點中沒包含具體的交易信息,就給交易證明帶來一些困難。在比特幣系統中採用Merkle proof方法。輕節點想要證明圖中tx(黃色框代表的某一筆)交易,輕節點保存了區塊頭信息,需要向全節點請求區中三個紅色H()哈希信息,並在本地計算三個綠色H()哈希信息,並最終計算Merkle root信息,如果計算得到的Merkle root信息和輕節點保存在區塊頭中的Merkle root信息一致,那麼證實了區塊中確實記錄了該筆交易。

Merkle proof在證明過程中,需要向周圍全節點請求紅色H()信息,似乎給惡意的節點篡改tx和H()使最終Merkle root合法機會,但是Hash函數的抗碰撞性保證構造出Merkle root是不可行的。惡意用戶爲證明非法的tx,僞造H()生成Merkle root是要花費計算資源暴力求解的。

這個暴力求解要比挖礦難度大得多,挖礦只要求hash結果小於target,而僞造Merkle root要算出指定的hash結果,這個值是唯一的。

想要證明一個區塊中不包含一筆交易,在比特幣系統是比較費力的,需要把區塊的內容都發生給輕節點。可以採用Sorted merkle tree結構,首先將交易列表排序(採用交易Hash值排序),再按照Merkle tree構造Merkle root。當需要證明一筆交易不存在時,根據排序的交易列表,找到左右2個交易,並提供Merkle proof,如果證明了這2個交易位置,就可以證明了不存在特定的交易。

四、 BTC協議

4.1 雙花與數字貨幣

央行可以發行一種和紙幣對應的數字貨幣,數字貨幣中包含面額、編號和央行數字簽名。如下圖所示:

當Alice向Bob花費100元時,可以將手中的100元數字貨幣轉交給Bob。但是,這種數字貨幣會有一個嚴重問題,Alice可以複製這個數字貨幣,並在下一次支付時候,再次使用。這個就是雙花問題double spending。

採用這樣的數字貨幣,每筆交易都必須有央行參與,確定交易的數字貨幣是否屬於支付方,並在支付成功後,將數字貨幣所屬權修改爲收款方。那麼,這樣的交易不需要貨幣支撐,就和我們日常的支付寶微信支付一樣了。

4.2 去中心化數字貨幣

比特幣是一種去中心化的貨幣,解決了2個問題:①誰來發行貨幣②解決雙花問題。

貨幣的發行是根據比特幣協議產生,由獲得記賬權的礦工取得的。當礦工挖礦的時候,交易列表中記錄一筆“鑄幣”交易,由礦工獲得當前區塊的出塊獎勵。在時間線上,可能與我們的認知順序不一樣,你可能會認爲礦工首先獲得了記賬權,再獲得出塊獎勵,但實際情況是在出塊之前,礦工就會將自己獲得出塊獎勵的交易記錄打包到區塊中,再進行挖礦,當挖礦成功並得到確認之後自然得到出塊獎勵。

解決雙花的方法是,每一筆交易都要指明花費來源於哪筆交易。下面是比特幣系統中交易的例子,A通過挖礦獲得10BTC,在下面A將這10BTC轉給B 5BTC,轉給C 5BTC。

4.3 比特幣中交易

一個典型的比特幣交易如下圖,連續4個區塊,每個區塊記錄只記錄了一筆交易。

在第一個區塊中,A賬戶通過記賬獲得10BTC的記賬獎勵;第二個區塊記錄,A花掉了10BTC,轉給B 5BTC,轉給C 5BTC,A的10BTC來源是第一個區塊;第三個區塊記錄B花掉5BTC,轉給C 2BTC,轉給D 3BTC,來源是第二個區塊記錄交易;第三個區塊記錄C轉給E 7BTC,來源與第二個區塊C獲得的5 BTC和第三個區塊中C獲得的2 BTC。

以上例子中,每個區塊只記錄了一筆交易,而真實的比特幣系統中會記錄多筆(幾千)筆交易。

每筆交易,都需要轉賬者簽名,收款方就是對應的公鑰地址。A轉給B 5BTC,指明幣的來源是上一筆鑄幣交易,通常A要說明自己的公鑰,並在這筆交易上附上自己的數字簽名。

這筆交易在比特幣網上擴散,礦工節點要驗證交易的合法性,用A的公鑰驗證交易的數字簽名,同時驗證A的公鑰和交易來源交易的收幣用戶是同一個用戶。

一筆轉賬交易的地址,通常用用戶公鑰的hash值,這樣不會直接顯示用戶的公鑰,有更好的匿名性。

4.4 比特幣共識機制

在比特幣網路中,每個賬戶都可以發佈交易,每個節點獨立打包交易,最終對賬本內容取得分佈式共識(distributed consensus)。

分佈式系統相關理論:

CAP therem:Consistencey Availablitity Partion tolerance

Paxos

在比特幣中,分佈式共識是通過投票機制達成共識,採用比拼算力的方法,實現投票權。投入的算力越多,獲取記賬權概率越大。

聯盟鏈hyperledger fabric,合法的用戶才能投票。

區塊鏈中,可能出現臨時性分叉。如圖,兩個礦工同時獲得記賬權,礦工會挑選一條鏈,繼續往下挖,最終會產生一條最長鏈,其他的礦工都會沿着合法鏈往下繼續挖礦,而分叉的鏈條被遺棄,沒有任何作用。

4.5 出塊獎勵

在比特幣系統中,通過挖礦獲得區塊記賬權的礦工獲得比特幣獎勵。在初始階段,每個區塊獲得50 BTC,約定每隔21萬個區塊,獎勵數減半。

210000∗10 / 365∗24∗60≈4

每個區塊的出塊時間約爲10分鐘,21萬個區塊約佔用4年時間。2009年,BTC初始時出塊獎勵是50BTC,2013年時變爲25BTC,2017年是12.5BTC。離我們最近出塊獎勵變化時間是2021年,BTC出塊獎勵降爲6.25BTC。2020年2月,比特幣的價格約爲9766美元,那麼出塊獎勵摺合成美元就是12.2萬美元。

4.6 交易費

除了出塊獎勵外,獲得記賬權的礦工,還可以獲得交易費。交易費是指,由支付方在每筆交易中除了應收金額外,多付給礦工的BTC,爲了鼓勵礦工將交易打包到區塊中,那麼交易就可以儘早確認。交易費不是必須的,交易中也可以不包含交易費。

當前,比特幣系統中,平均有10萬條交易等待打包確認,而每個區塊有1M大小限制,而礦工更願意將包含交易費的區塊。如下圖的交易,COINBASE交易就是礦工的鑄幣交易,礦工獲得的獎勵除了12.622 BTC,當前的出塊獎勵是12.5 BTC,額外的0.122就是這個區塊打包全部交易的交易費。

五、 BTC實現

5.1 UTXO

在比特幣中,採用transcation-base ledger,即基於交易的記賬本。通常大家更容易理解account-base ledger基於賬戶的記賬本。由於採用基於交易的記賬本,因此在比特幣系統中很難確定一個賬戶下擁有多少比特幣。

比特幣系統中,全節點負責維護UTXO數據結構,保存沒有花費的交易。全節點將UTXO存儲內容中,並用來驗證收到的交易的正確性,當交易的輸入是保存在UTXO中的未花費交易,那麼交易來源的合法性是正確的。

當轉賬交易發生之後,會在UTXO中增加一條記錄。UTXO保存在內存中,一方面是方便快速查找,另一方面由於比特幣是基於transcation-base ledger,可以通過重放交易記錄重新生成UTXO,因此可以不用持久化存儲。

問題:沒找到資料UTXO的數據結構,如何快速驗證交易是否存在在UTXO中。

有些交易長期保存在UTXO中,一些由於丟失私鑰,那麼這些比特幣再也無法交易。還有一些,例如中本聰早期挖礦所得,他本人也不用來交易,也會長期存儲在UTXO系統中。

5.2 Bernulli trail

提到挖礦是一個無記憶性的過程Memoryless,符合Bernulli trail。

挖礦的工程如果不是Prograss free,那麼算力強的礦工會取得不成比例的優勢。

這塊的理解,以拋硬幣爲例也是一個bernulli trail,memory less的過程,我想要一個正面的結果,和我前面幾次拋硬幣獲得反面的結果都沒有關係。在比特幣挖礦過程中,我計算一個nonce,再計算下一個nonce時是否能滿足條件都是不可知的。

這個Bernulli process過程,和窮舉密鑰攻擊的過程相識,但不一樣。窮舉密鑰,在密鑰空間中存在這樣的密鑰,計算一個結果就排除一個結果。但是挖礦過程,就好像拋一個2^256個面的骰子,只有2^target個面是符合條件的。

5.3 挖礦的意義

挖礦本身沒有意義,但是挖礦是比特幣安全的保障。Bitcoin is secured by mining。在分叉攻擊的例子中,惡意節點發佈一個包含回滾交易的區塊,網絡上的節點有可能按照惡意路徑繼續挖礦,造成交易信息失敗。

防止分叉交易的方法,等待該鏈上多產生幾個區塊,又叫多等待幾個確認。此處惡意節點想要回滾交易,就不是爭奪一個區塊的記賬權,而是連續幾個區塊的記賬權,難度很大。在攻擊時,攻擊者要沿着自己構造的區塊往下生產,而網絡上的其他礦工默認沿最長合法鏈挖礦挖礦,會保持正常的交易繼續進行。

通過這個分叉攻擊的例子,說明了挖礦是區塊鏈安全的保障。在實際中,交易要等6個確認,纔算被認爲是生效。

上圖中,M首先轉A若干BTC,同時發佈一個區塊,包含一個M轉給M‘的區塊,如果下面M轉給M’的交易生效,根據UTXO的記錄上面區塊記錄的M轉給A的交易就不會生效。

5.4 Selfish mining

惡意節點挖到節點後,先不發佈,並沿着自己挖到的區塊繼續挖礦,等有其他節點發布了,發佈2個連續的區塊。目的是浪費其他礦工的算力。

但是這種selfish mining是有風險的,不發佈區塊,就得不到區塊獎勵,連續領先挖出2個區塊的概率是很低的。

通常,正常的節點收到其他節點發布的區塊,都會停下自己的挖礦工作,沿着發佈區塊往後繼續挖礦。因爲挖礦是pregress free,繼續挖礦和沿着新區塊挖礦意義一樣。

六、 BTC網絡

6.1 網絡結構

節點之間採用flooding泛洪廣播,網絡層採用p2p網絡,應用層採用區塊鏈協議。

比特幣網絡的設計思想是簡單魯棒。節點退出網絡,其他節點一段時間沒有收到該節點的信息,刪除保存的這個節點信息。比特幣區塊鏈網絡忽略物理環境的拓撲結構,因此鄰近節點可能是在真實環境中距離很遠的節點,秉持越簡單越魯棒的特點。

比特幣區塊大小1M字節,大約花費幾十秒廣播到全部網絡節點上。

6.2 廣播

每個節點都會廣播收到的交易信息和區塊信息。

節點要維護一個接收交易的集合,這些交易都是經過廣播,且被認爲是合法的交易,但是由於去中心化的特性,還會遇到一些情況。

節點保留了一個A->B的交易,又收到一個A->C的交易,2筆交易指向同一筆未花費交易,此時節點會丟棄收到A->C 交易。

如果節點收到一個區塊,包含A->C的交易,那麼待上鍊A->B就是非法的,節點會丟棄這筆交易。

七、 挖礦難度

7.1 難度

比特幣中設定合法的區塊,區塊頭的哈希值必須小於等於target。採用的哈希算法是SHA-256,計算哈希的結果是256位,將結果看成一個整數,與target轉化成256位整數比較。挖礦的過程就是找到nonce,計算block header的哈希滿足上面的條件。公式描述了target和挖礦難度之間的關係,target越小難度越大。difficulty_1_target初始時比特幣的難度。

$difficulty =\frac {difficulty\_1\_target}{target}$

7.2 難度調整

爲保證比特幣的出塊時間在10分鐘左右,比特幣系統會根據前一段時間的出塊時間調整target值。每隔2016個區塊,採用下面的公式對target調整。expect_time就是10分鐘,如果actual_time大於10分鐘,target變大,降低難度;actual_time小於10分鐘,target變小,難度增大。難度調整還有一個限制,調整幅度不能超過4倍和1/4。

$target =target*\frac {actual_time\_time}{expected\_time}$

比特幣系統中,如果區塊時間設置的更短,例如5分鐘,那麼比特幣系統中會更容易出現分叉,如圖所示。系統中出現多分叉時,相當於系統中合法節點算力被分散,那麼系統更容易被分叉攻擊。10分鐘是比特幣設計者中本聰設定的。

八、 BTC 挖礦

8.1 挖礦

比特幣系統中有全節點和輕節點,全節點是挖礦,即爭奪記賬權、打包區塊。挖礦的過程就是窮舉nonce,使區塊頭哈希值小於等於target。

挖礦的過程是無記憶性的memoryless,又稱progress free。之前的章節解釋過這一個過程,比如拋硬幣,我想要拋一個正面向上的硬幣,和已經拋過的過程無關係。

每嘗試一個nonce,都是在一定概率下滿足挖礦條件,和之前嘗試了多少次nonce沒關係。這種memoryless的特性,使得挖礦成功的概率等於節點佔總算力的比例。

8.2 挖礦方法

比特幣的mining puzzle是哈希算法,流行的運算工具有CPU、GPU、ASIC等。

利用CPU挖礦,CPU中的大部分運算單元和內存都沒有充分利用,挖礦速度也不高。利用GPU挖礦,可以並行計算。ASIC是專用芯片,由硬件實現算法,速度更快。

通常的礦機都是ASIC,高度並行化的專用芯片。但是ASIC製作成本高、週期長,設計一款挖礦通常需要一年時間,投入巨大。而礦機的淘汰速度也很快,過一段時間就有更好的礦機問世,比老款礦機速度更快,老款礦機就會因電費的原因被淘汰。

8.3 礦池挖礦

礦池可以將分散的算力集中起來,一個礦池可以管理很多個礦工,礦池負責打包區塊,礦工負責接收礦池的任務進行hash運算。

礦池中的礦工按貢獻率分配挖礦獎勵,礦工的貢獻也是採用工作量證明的方式。實際,礦池要求礦工提交一個較比特幣puzzle難度低的結果,比如比特幣puzzle要求包含70個0,而礦池要求puzzle是60個0。

礦工每提交一個這樣的結果,被認爲比較了一個share。這些share中可能包含了符合比特幣要求的結果,礦池就可以獲得收益。而絕大部分的share是沒有意義的,僅僅作爲礦工的工作量證明。

從概率上分析,加入礦池的礦工的收入期望並沒有增加,獲得的收益任然是礦工佔全部節點算力的比例。但是,通過加入礦池,礦工收入的穩定性提高了。一些礦池爲了吸引礦工加入,會爲礦工提供額外的獎勵,這也導致了超大型礦池的出現。

出現超大型礦池可能佔全部節點算力的51%,這種情況在區塊鏈歷史上是出現過的。大型礦池可以利用51%算力,進行分叉攻擊。而獲取51%攻擊想要盜取其他人賬戶中的比特幣是辦不到的。

礦池中是否有惡意的礦工?當礦工挖到了符合比特幣puzzle的結果,但是不將這個結果發送給礦池,礦池就不會得到出塊獎勵。礦池之間是競爭關係,可能將自己的節點加入對手的礦池,搞一些破壞,分散對手的算力。

九、 BTC腳本

9.1 交易數據結構

比特幣系統在網絡中廣播交易,數據結構如下圖。

其中vin被稱作輸入腳本,vout被稱爲輸出腳本。交易是否合法,首先要檢查比特幣的來源,輸入腳本中要包含交易中比特幣來源的證明,要素是簽名。輸出腳本中要包含接收方的地址。比特幣系統中,不會校驗輸出腳本的合法性。

比特幣被稱作可編程的加密貨幣,交易過程中需要執行輸入輸出腳本。在比特幣系統,全部幣都來至挖礦,即鑄幣交易。在鑄幣交易中,沒有輸入腳本,輸出腳本指明瞭礦工的地址。可以直接用公鑰地址作目的地址[ws1] ,也可以用礦工公鑰地址hash作爲目的地址。

  1. 礦工挖礦成功,獲得記賬權,得到鑄幣獎勵並寫入區塊鏈。
  2. 當其他節點收到廣播的新區塊,就會修改本地的UTXO,增加一條PK1賬戶轉入25BTC的記錄。
  3. 當PK1要花掉這個25BTC時,要構造一條交易,在交易中指明交易id(txid),並指明將錢轉給PK2,並對交易用PK2對應的私鑰簽名。
  4. 當其他節點收到這個交易的時候,會校驗是否與待上鍊交易衝突。
  5. 全節點還要驗證UTXO中存在txid交易,再用PK1公鑰驗證簽名,驗籤通過說明是PK1發起的交易,最終證明交易合法。

9.2 輸入腳本和輸出腳本

比特幣系統中,可以看做以交易tx驅動UTXO賬本記錄。通常一筆交易要在UTXO中花費掉記錄,並生成新的記錄。

UTXO中添加記錄,被稱爲將比特幣鎖定在賬本上,與鎖定對應,要花掉比特幣的行爲稱作解鎖。一筆交易通常解鎖、鎖定過程。下圖中,A轉給B 5BTC和C 5BTC,A花費鑄幣交易稱作解鎖,在UTXO中產生B(5) C(5)稱作鎖定。

輸入腳本的目的就是提供解鎖證明,與之對應鎖定腳本可以將比特幣鎖定在一下4種類型:

  1. 鎖定在公鑰中。即支付對象是接收者的公鑰,pay to public key(P2PK)
  2. 鎖定在公鑰哈希中。即支付對象是接收者的公鑰哈希,可以隱藏接收者的公鑰信息,pay to public key hash(P2PKH)
  3. 鎖定在鎖定在多重賬戶中。支付對象以多個接受者爲整體。
  4. 鎖定在一段腳本中。Pay to Script Hash(P2SH)

9.3 腳本實例

9.3.1 P2PK型交易

f418交易產生2個結果,ea44交易花掉了10BTC,交易信息如圖(注f418和ea44是txid的前4位,交易txid也是交易的hash)。2筆交易的地址如下:

https://www.blockchain.com/en/btc/tx/f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16

https://www.blockchain.com/en/btc/tx/ea44e97271691990157559d0bdd9959e02790c34db6c006d779e82fa5aee708e

一、f418輸出腳本:

查看交易信息,重點關注輸出outputs,輸出腳本Pkscript如下:

04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c

OP_CHECKSIG

其中:

  • 04:操作符 OP_PUSHDATA
  • ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c:公鑰64位,公鑰由2個32字節數組成,這裏轉換爲16進製表示是64位。
  • OP_CHECKSIG:操作符

點擊HEX按鈕,顯示16進制信息。這段HEX中,開頭4104、結尾ac都是操作符,這一段HEX字符就是輸出腳本,就是鎖定腳本。

4104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84cac

二、ea44腳本輸入:

通過1Q2T(UXTO)指明瞭來源,引用Pkscript信息。Sigscript是簽名信息。

P2PK(Pay to Public Key)的執行腳本以堆棧方式執行,

input script:
PUSHDATA(Sig)
output script:
PUSHDATA(PubKey)
CHECKSIG

執行過程如下,最終結果爲TRUE證明校驗通過。

9.3.2 P2PKH型交易

P2PKH(pay to public key hash)是在交易中,指明收貨地址的hash值。用Hash值代替公鑰,可以隱藏公鑰信息,而且Hash值的長度比公鑰的長度短,數據量小。執行腳本如下:

input script:
PUSHDATA(Sig)
PUSHDATA(PubKey)
output script:
DUP
HASH160
PUSHDATA(PubKeyHash)
EQUALVERIFY
CHECKSIG

實際例子

https://www.blockchain.com/en/btc/tx/c0cb92ca8e41070233bf965d808b0fc4bac144dab05690b17823fac3e184c57b

https://www.blockchain.com/en/btc/tx/921af728159e3019c18bbe0de9c70aa563ad27f3f562294d993a208d4fcfdd24

在921a交易中給出了公鑰和交易簽名,解鎖c0cb腳本的輸出交易。

9.3.3 P2SH型交易

P2SH(pay to script hash)是指交易的地址是一段代碼的hash值,與之與對應解鎖交易必須給出這段交易的原文script,而且運行script必須得到正確的結果。

input script:
…
PUSHDATA(Sig)
…
PUSHDATA(serialized redeemScript)
output script:
HASH160
PUSHDATA(redeemScriptHash)
EQUAL

input script要給出一些簽名(數目不定)及一段序列化的redeemScript。驗證時分兩步:第一步驗證這段序列化的redeemScript是否與output script中的哈希值匹配。第二步反序列化並執行redeemScript ,配合前邊的簽名是否可以執行通過。

實際例子

https://www.blockchain.com/en/btc/tx/0ac29fc675909eb565a0984fe13a47dae16ca53fb477b9e03446c898b925ab6b

https://www.blockchain.com/en/btc/tx/bc26380619a36e0ecbb5bae4eebf78d8fdef24ba5ed5fd040e7bff37311e180d

腳本執行

此例中,redeemscript解析如下:

52 #2
21027ca87e1aa2595ec7771afee8fdc6efdbc301b8370c4386731b4bd82247dc74a3
#pk1
21022cc9874ba092095dda47a4e4edb1781c43c35b3ec0429ac005df37b9d6eec94b
#pk2
21035739f07de25c205525d81b126ed87bc30377e688705072d186e4f5c88908ce3a
#pk3
53 #3
ae #checkMultisig

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章