比特幣有時也稱為可程式貨幣。它的數位性質,使得用戶在設定如何使用資金的條件時擁有很大的靈活性
討論比特幣時,我們會提到錢包和代幣。但我們也可以把錢包當作鑰匙,把代幣當作支票,把區塊鏈看成一排又一排帶鎖的保險箱。每個保險箱都有一個細小的插槽,讓任何人都可以存入支票或查看保險箱裡有多少價值。然而,只有鑰匙持有者才能為保險箱開鎖。
如果鑰匙持有者想把錢給其他人,就會打開保險箱。他們會開一張引用舊支票的新支票(舊支票隨後會被銷毀),並將其重新鎖在收款人可以打開的箱子中。為了花掉這筆錢,新的收款人需要重複這個過程。
在本文中,我們將更深入地了解腳本,這是一種由比特幣網路上的節點進行解釋的程式語言。腳本管理前面提到的保險箱的上鎖/開鎖機制。
採用上述類比,可以說每筆交易都有兩個部分 — 鑰匙(用於為保險箱開鎖)和鎖。您需要用鑰匙打開包含要寄出的支票的箱子,然後將新的支票添加至另一個使用不同鎖的新箱子。要花掉新箱子裡面的錢,您需要另一把鑰匙。
就這麼簡單。系統中的鎖的類型可能會有一些變化。有些保險箱需要您提供多個多個鑰匙,其他保險箱則需要您證明您知道某個密碼,總之可以設定很多條件。
我們的鑰匙就是我們所說的scriptSig,鎖則是我們所說的scriptPubKey。如果我們更詳細地觀察這些元件,我們會發現它們實際上由資料位元和程式碼區塊組成。當它們結合在一起時,就形成了一個小程式。
當您進行交易時,您就是在向網路廣播該組合。每個接收到這筆交易的節點都將檢查這個程序,該程序將告知節點這比交易是否有效。如果無效,交易就會被廢棄,您將無法使用鎖定的資金。
您持有的支票(代幣)稱為未花費的交易輸出(UTXO)。只要能提供與這把鎖相符的鑰匙,任何人都可以使用這筆資金。具體來說,鑰匙是scriptSig,鎖是scriptPubKey。
如果UTXO在您的錢包內,它們可能會有一個條件,即只有能證明該公鑰所有權的人才能解鎖這些資金。如需解鎖資金,您需要提供一個包含數位簽章的scriptSig,使用對應到scriptPubKey中指定公鑰的私鑰。一切很快就會變得清晰起來。
腳本是一種基於堆疊的語言。這就意味著,當我們閱讀一組指令時,我們會將它們放在被視為垂直的欄位中。例如,列表A、B、C將產生一個堆疊,A位於底部,C位於頂部。當指令告訴我們要做某事時,我們就會從堆疊的頂部開始操作一個或多個元素。
元素A、B和C被加入並從堆疊中“彈出”。
我們可以區分資料(例如簽章、雜湊和公鑰)和指令(或操作碼)。指令刪除資料並對其進行處理。以下是一個很簡單的腳本範例:
<xyz> ; <md5 hasher> <d16fb36f0911f878998c136191af705e> ;
紅色部分錶示數據,藍色部分錶示操作碼。我們從左到右讀取,所以我們先把字串<xyz>放到堆疊上。接下來是<md5 hasher>操作碼。這個操作碼在比特幣中並不存在,但我們假設它刪除了堆疊頂部的元素(<xyz>),並使用MD5演算法進行了哈希。隨後將輸出添加回堆疊。這裡的輸出恰好是d16fb36f0911f878998c136191af705e。
太巧了!我們要加入的下一個元素是<d16fb36f0911f878998c136191af705e>,因此,現在我們的堆有兩個個相同的元素。最後,<check if equal>在頂部彈出兩個元素,並檢查它們是否相等。如果相等,則將<1>加至堆疊。如果不相等,則將<0>加至堆疊。
我們已經到了指令清單的最後。我們的腳本可能會以兩種方式失敗 — 如果剩餘元素為零,或者如果某些條件不滿足時,其中一個運算符將導致其失敗。在這個例子中,我們沒有任何這樣的運算符,最後得到一個非0元素(<1>),因此我們的腳本是有效的。這些規則也適用於真正的比特幣交易。
上述範例只是一個虛構的程式。現在我們來看一些實際的範例。
支付到公鑰(P2PK)非常簡單。它設計將資金鎖定至特定的公鑰。如果您想以這種方式接收資金,就需要向發送者提供您的公鑰,而不是比特幣地址。
中本聰和Hal Finney在2009年的第一筆交易就是P2PK交易。這種結構在比特幣早期就被大量使用,但如今,支付到公鑰哈希(P2PKH)已經在很大程度上取代了它。
P2PK交易的鎖定腳本遵循<public key> OP_CHECKSIG的格式。就這麼簡單。您可能已經猜到,OP_CHECKSIG會根據提供的公鑰檢查簽名。因此,我們的scriptSig將會是個簡單的<signature>。記住,scriptSig是開鎖的鑰匙。
沒有比這更簡單的了。簽名被加入到堆疊中,隨後是公鑰。OP_CHECKSIG同時彈出簽章和公鑰,並根據公鑰驗證簽章。如果二者匹配,則向堆疊中加入<1>。否則加上<0>。
出於我們即將在下一節詳細說明的原因,P2PK實際上已經不再使用。
支付到公鑰哈希(P2PKH)是現在最常見的交易類型。除非您特地去下載過時的軟體,否則您的錢包很可能會默認採取這種交易。
P2PKH的scriptPubKey如下:
OP_DUP OP_HASH160 <public key hash> OP_EQUALVERIFY OP_CHECKSIG
在我們在介紹scriptSig之前,我們先來分析一下新的操作碼的作用:
OP_DUP彈出第一個元素,並複製這個元素。隨後,它將二者同時添加回堆疊。通常,這樣做是為了在不影響原始元素的情況下對副本進行操作。
這將彈出第一個元素,並進行兩個雜湊。第一輪將使用SHA-256演算法進行雜湊。隨後使用RIPEMD-160演算法對SHA-256輸出進行雜湊。結果輸出被加回堆疊。
OP_EQUALVERIFY由另外兩個運算子OP_EQUAL和OP_VERIFY組合而成。 OP_EQUAL彈出兩個元素,並檢查其是否相同。如果相同,則將1新增至堆疊。如果不相同,則添加0。 OP_VERIFY彈出頂部元素,並檢查其是否為True(也為非0)。如果不是,則交易失敗。綜合起來,如果頂部兩個元素不匹配,則OP_EQUALVERIFY會導致交易失敗。
這次,scriptSig如下:
<signature> <public key>
您需要提供簽名以及對應的公鑰來解鎖P2PKH輸出。
您可以透過上面的GIF詳細了解。它與P2PK腳本並沒有太大的不同。我們只是添加了一個額外的步驟,來檢查公鑰是否與腳本中的雜湊相符。
不過,有一點要注意。在P2PKH鎖定腳本中,公鑰是不可見的 — 我們只能看到它的哈希。如果我們前往區塊鏈瀏覽器並查看尚未被花費的P2PKH輸出,我們將無法確定其公鑰。只有當收款人決定轉移資金時才會被揭露。
這有幾個好處。首先就是,公鑰哈希比完整的公鑰更容易傳遞。正是出於這個原因,中本聰在2009年推出了公鑰哈希。 公鑰哈希就是我們現在所知的比特幣地址。
第二個好處是,公鑰雜湊可以為量子計算提供額外的安全層。因為我們的公鑰只有在我們花費資金之後才會被知道,因此其他人就更難計算私鑰。他們必須逆轉兩輪哈希(RIPEMD-160和SHA-256),才能得到私鑰。
➟ 想要開啟加密貨幣之旅?立即前往幣安購買比特幣吧!
支付到腳本哈希(P2SH )對於比特幣來說是一個非常有趣的發展。它允許發送者將資金鎖定到腳本的哈希 — 而無需知道腳本實際做了什麼。以下面的SHA-256雜湊為例:
e145fe9ed5c23aa71fdb443de00c7d9b4a69f8a27a2e4fbb1fe1d0db6583f1輸入來鎖定資金。然而,花費資金的人需要提供用於哈希它的腳本,並需要滿足該腳本的條件。
上面的雜湊就是透過下面的腳本來建立:
<multiply by 2> <4> <check if equal>
如果您想花費綁定到這個scriptPubKey的代幣,您不僅要提供這些命令。您還需要一個scriptSig,使完成的腳本的值為True。在這個例子中,即為您<multiply by 2>以獲得<4>結果的元素。當然,這意味著我們的腳本只是<2>。
在實際情況中,P2SH輸出的scriptPubKey為:
OP_HASH160 <redeemScript hash> OP_EQUAL
此處沒有新的運算子。但是,我們確實有<redeemScript hash>作為一個新元素。顧名思義,這就是我們需要提供用於贖回資金額腳本哈希(稱之為redeemScript)。 scriptSig將根據redeemScript中的內容而變化。不過,通常情況下,您會發現它是簽名和附加公鑰的某種組合,隨後是(強制性的)redeemScript:
<signature> <public key> <redeemScript>
我們的計算與目前所見的堆疊執行略有不同。它分為兩個部分。第一部分僅檢查您是否提供了正確的哈希。
您會注意到,我們沒有對redeemScript前面的元素執行任何操作。它們在這個時候還不會被用到。我們已經到了這個小程式的末尾,頂部元素為非0。也就是說,它是有效的。
但我們還沒完成。網路節點將這個結構識別為P2SH,因此它們實際上已經讓scriptSig的元素在另一個堆疊中等候。這就是要用到簽章和公鑰的地方。
到目前為止,我們一直將redeemScript視為一個元素。但現在,它會被解釋為指令,這可以是任何東西。我們以P2PKH鎖定腳本為例,我們必須提供與<redeemScript>中的<public key hash>匹配的<signature>和<public key>。
一旦您的redeemScript被擴展,就可以看到我們的情況看起來與常規P2PKH交易完全一樣。之後,您只需要像正常程式一樣運行它。
我們已經示範了所謂的P2SH(P2PKH)腳本,但您不太可能在自然環境中找到這樣的腳本。沒有什麼可以阻止您製作一個,但卻不會為您帶來任何好處,而且最終會佔用更多的區塊空間(因此也成本更高)。
P2SH通常適用於多重簽章或SegWit相容交易之類的情況。多重簽名交易的規模可能非常之大,因為它們需要多個金鑰。在實施付費到腳本雜湊之前,發送者必須在其鎖定腳本中列出所有可能的公鑰。
但對於P2SH,無論消費條件多麼複雜,它都不會產生影響。 redeemScript的哈希始終為固定大小。因此,成本會轉移給想要解鎖鎖定腳本的使用者。
SegWit相容性是P2SH可以派上用場的另一個範例(我們將在下一節詳細討論交易結構的不同)。 SegWit是一個軟分叉,它導致了區塊/交易格式的改變。由於它是一項可選擇的升級,因此並非所有錢包軟體都能識別這些變更。
如果客戶端將SegWit腳本雜湊封裝在P2SH中,這一點無足輕重。就像所有這種類型的交易一樣,它們不需要知道解鎖的redeemScript是什麼。
如需取得更全面的SegWit介紹,請參閱《隔離見證新手指南》。
如需理解SegWit中的交易格式,您只需要知道我們不再只有scriptSig和scriptPubKey。現在,我們還有一個被稱為“見證”的新領域。我們先前儲存在scriptSig中的資料被移到見證,因此scriptSig為空。
如果您遇到過以“bc1”開頭的地址,那麼,這些地址就是我們所說的SegWit原生(而不是SegWit兼容,因為它們是P2SH地址,因此它們以“3&rdquo ;開頭)。
支付到見證公鑰哈希(P2PKH)是P2PKH的SegWit版本。我們的見證如下:
<signature> <public key>
您會注意到,這與P2PKH中的scriptSig相同。在這裡,scriptSig是空的。同時,scriptPubKey類似如下:
<OP_0> span> <public key hash>
這看起很奇怪,對吧?讓我們比較簽章、公鑰及其雜湊的運算碼在哪裡?
我們在這裡並沒有展示額外的運算符,因為接收交易的節點根據<public key hash> ;的長度知道如何處理它。它們會計算長度,並理解它必須以與傳統P2PKH交易相同的方式運行。
未升級的節點不知道如何以這種方式解釋交易,但這無關緊要。在舊的規則下沒有見證,因此它們會讀取一個空的scriptSig和一些資料。它們會對其進行評估,並將其標記為有效 — 在它們看來,任何人都可以使用這些輸出。這就是為什麼SegWit會被認為是向後相容的軟分叉。
支付到公鑰哈希(P2PKH)是新的P2SH。如果您已進展至這一步,或許就能弄清楚它的運作方式了,但無論如何,我們都會過一遍。我們的見證是我們通常放在scriptSig中的內容。例如,在打包P2PKH交易的P2WSH中,它可能看起來是這樣子的:
<signature> <public key>
以下是我們的scriptPubKey:
<OP_0> ; <public key hash>
這裡採取相同的規則。 SegWit節點讀取腳本雜湊的長度並確定它是P2WSH輸出,其評估方式類似於P2SH。同時,舊節點只不過將其視為任何人可以花費的輸出。
在這篇文章中,我們對比特幣的建構區塊有了一定了解。讓我們來快速總結一下:
腳本類型 | 描述 |
---|---|
支付到公鑰(P2PK) | 將資金鎖定在特定公鑰 |
支付到公鑰哈希(P2PKH) | 將資金鎖定到特定公鑰哈希(即位址) |
支付到腳本哈希(P2SH) | 將資金鎖定到收款人可以提供的腳本的哈希 |
支付到見證公鑰哈希(P2PKH) | P2PK的SegWit版本 |
支付到公鑰哈希(P2PKH) | P2SH的SegWit版本 |
深入研究比特幣後,您就會開始理解為何它具有如此大的潛力。交易可能有多個不同的組成部分構成。透過操縱這些建構區塊,用戶可極為靈活地為使用資金的方式及時間設定條件。