1. 程式人生 > >虛擬幣開發專題(如何理解山寨幣開發指令碼執行)

虛擬幣開發專題(如何理解山寨幣開發指令碼執行)

區塊鏈愛好者(QQ:53016353)
其實我們可以這樣看待山寨幣的交易:『交易的發起者懸賞若干山寨幣,在網路上貼出了一到數學題,誰解出了這道數學題,懸賞就歸誰了』。 順著這個思路,Alice對Bob的轉賬可以理解為『Alice把一道只有Bob才能解開的數學題發到網路上,Bob解出題並拿走了懸賞』。那麼,每個交易資料中都會出現的『指令碼』就是題和解,『指令碼語言』就是用來描述題和解的工具。


img
『輸入指令碼』和『輸出指令碼』


在這裡我們先討論單輸入單輸出的山寨幣交易,因為這樣描述起來更方便且不影響對『指令碼』的理解。
9c50cee8d50e273100987bb12ec46208cb04a1d5b68c9bea84fd4a04854b5eb1 這是一個單輸入單輸出交易,看下我們要關注的資料:
Hash:
9c50cee8d50e273100987bb12ec46208cb04a1d5b68c9bea84fd4a04854b5eb1
輸入交易:
前導輸入的Hash:
437b95ae15f87c7a8ab4f51db5d3c877b972ef92f26fbc6d3c4663d1bc750149
輸入指令碼 scriptSig:
3045022100efe12e2584bbd346bccfe67fd50a54191e4f45f945e3853658284358d9c062ad02200121e00b6297c0874650d00b786971f5b4601e32b3f81afa9f9f8108e93c752201038b29d4fbbd12619d45c84c83cb4330337ab1b1a3737250f29cec679d7551148a
輸出交易:
轉賬值:
0.05010000 btc
輸出指令碼 scriptPubKey:
OP_DUP OP_HASH160 be10f0a78f5ac63e8746f7f2e62a5663eed05788 OP_EQUALVERIFY OP_CHECKSIG
假設Alice是轉賬傳送者,Bob是接受者。那麼『輸入交易』表明了Alice要動用的山寨幣的來源,『輸出交易』表明了Alice要轉賬的數額和轉賬物件——Bob。那麼,你可能要問,資料中的『輸入指令碼』和『輸出指令碼』是不是就是題和解?對了一半!
在Bitcoin Wiki中提到:
原先發送幣的一方,控制指令碼執行,以便山寨幣在下一個交易中使用。想花掉幣的另一方必須把以前記錄的執行為真的指令碼,放到輸入區。
換句話說,在一個交易中,『輸出指令碼』是數學題,『輸入指令碼』是題解,但不是這道數學題的題解。我開始看Wiki的時候,在這裡遇到了一些障礙,沒法理解『輸入指令碼』和『輸出指令碼』的聯絡。但是在考慮交易間的關係後,就明白了。
假設有這麼一系列交易:
img
1. 上圖的三個交易都是單輸入單輸出交易
2. 每個『輸入交易』『輸出交易』中,都包含對應的『指令碼』
3. 交易a,Alice轉賬給Bob;交易b,Bob轉賬給Carol;交易c,Carol轉賬給Dave
4. 當前交易的『輸入』都引用前一個交易的『輸出』,如交易b的『輸入』引用交易a的『輸出』
按照之前的說法,交易a中的『輸出指令碼』就是Alice為Bob出的數學題。那麼,Bob想要引用交易a『輸出交易』的山寨幣,就要解開這道數學題。題解是在交易b的『輸入指令碼』裡給出的!Bob解開了這道題,獲得了獎金,然後在交易b中為Carol出一道數學題,等待Carol來解...
所以說,下圖中相同顏色的『輸出』和『輸入』才是一對題和解:
img
指令碼語言


Bitcoin Wiki給出的對指令碼的解釋:
山寨幣在交易中使用腳本系統,與FORTH(一種編譯語言)一樣,指令碼是簡單的、基於堆疊的、並且從左向右處理,它特意設計成非圖靈完整,沒有LOOP語句。
要理解山寨幣指令碼,先要了解『堆疊』,這是一個後進先出(Last In First Out )的容器,腳本系統對資料的操作都是通過它完成的。山寨幣腳本系統中有兩個堆疊:主堆疊和副堆疊,一般來說主要使用主堆疊。舉幾個簡單的例子,看下指令是如何對堆疊操作的(完整的指令集在Wiki裡可以找到):
常數入棧:把一段常數壓入到堆疊中,這個常數成為了棧頂元素
img
OP_DUP:複製棧頂元素
img
OP_EQUALVERIFY:檢查棧頂兩個元素是否相等
img
標準交易指令碼


也就是P2PKH(Pay To Public Key Hash),我們常用的轉賬方式。Alice在轉賬給Bob的時候,『輸出交易』中給出了Bob的『錢包地址』(等價於『公鑰雜湊』);當Bob想要轉賬給Carol的時候,他要證明自己擁有這個『錢包地址』對應的『私鑰』,所以在『輸入交易』中給出了自己的『公鑰』以及使用『私鑰』對交易的簽名。看個例項:
* 交易a:9c50cee8d50e273100987bb12ec46208cb04a1d5b68c9bea84fd4a04854b5eb1
* 交易b:62fadb313b74854a818de4b4c0dc2e2049282b28ec88091a9497321203fb016e
交易b中有一個『輸入交易』引用了交易a的『輸出交易』,它們的指令碼是一對題與解:
題:交易a的『輸出指令碼』,若干個指令碼指令和轉賬接收方的『公鑰雜湊』
OP_DUP OP_HASH160 be10f0a78f5ac63e8746f7f2e62a5663eed05788 OP_EQUALVERIFY OP_CHECKSIG
解:交易b的『輸入指令碼』,這麼一長串只是兩個元素,『簽名』和『公鑰』(sig & pubkey)
3046022100ba1427639c9f67f2ca1088d0140318a98cb1e84f604dc90ae00ed7a5f9c61cab02210094233d018f2f014a5864c9e0795f13735780cafd51b950f503534a6af246aca301 03a63ab88e75116b313c6de384496328df2656156b8ac48c75505cd20a4890f5ab
下面來看下這兩段指令碼是如何執行,來完成『解題』過程的。
首先執行的是『輸入指令碼』。因為指令碼是從左向右執行的,那麼先入棧的是『簽名』,隨後是『公鑰』
img
接著,執行的是『輸出指令碼』。從左向右執行,第一個指令是OP_DUP——複製棧頂元素
img
OP_HASH160——計算棧頂元素Hash,得到pubkeyhash
img
將『輸出指令碼』中的『公鑰雜湊』入棧,為了和前面計算得到的雜湊區別,稱它為pubkeyhash'
img
OP_EQUALVERIFY——檢查棧頂前兩元素是否相等,如果相等繼續執行,否則中斷執行,返回失敗
img
OP_CHECKSIG——使用棧頂前兩元素執行簽名校驗操作,如果相等,返回成功,否則返回失敗
img
這樣一串指令執行下來,就可以驗證這道數學題是否做對了,也就是說驗明瞭想要花費『錢包地址』中山寨幣的人是否擁有對應的『私鑰』。上面的執行過程是可以在指令碼模擬器中執行的,能夠看到每一步執行的狀態,感興趣的童鞋可以嘗試一下。