區塊鏈七-script

基於Java語言構建區塊鏈(七)—— 交易腳本(智能合約)

 Posted on 2018-05-02 |  In blockchain |  | 本文總閱讀量 342次php

 Words count in article: 2,600 |  Reading time ≈ 10html

上一篇 文章咱們引入 UTXOset 和 Merkle Tree 對交易流程作了些許優化,本篇文章咱們將介紹比特幣另外一個更加劇要的機制 —— 交易腳本。git

在介紹 UTXO的文章 中,咱們已經瞭解到比特幣的交易輸出由鎖定腳本鎖定,它只能被交易輸出所被指向的交易輸入中的解鎖腳本所解鎖,今天讓咱們來詳細討論一下它們的實現機制。github

 

交易詳情

現在,大多數比特幣網絡處理的交易是以「Alice付給Bob」的形式存在的。同時,它們是以一種稱爲「P2PKH」(Pay-to-Public-Key-Hash)腳本爲基礎的。然而,經過使用腳原本鎖定輸出和解鎖輸入意味着經過使用編程語言,比特幣交易能夠包含無限數量的條件。固然,比特幣交易並不限於「Alice付給Bob」 的形式和模式。」編程

這只是這個腳本語言能夠表達的可能性的冰山一角。稍後, 咱們將會全面展現比特幣交易腳本語言的各個組成部分;同時,咱們也會演示如何使用它去表達複雜的使用條件以及解鎖腳本如何去知足這些花費條件。數組

比特幣交易驗證並不基於一個不變的模式,而是經過運行腳本語言來實現。這種語言能夠表達出多到數不盡的條件變種。這也是比特幣做爲一種「可編程的貨幣」所擁有的權力。安全

咱們以《精通比特幣(第二版)》第二章節 中 Alice向Bob購買咖啡爲例,點擊查看該筆 交易詳情網絡

交易輸入:0.1000 BTC數據結構

手續費用:0.0005 BTC編程語言

支付費用:0.0150 BTC

找 零: 0.0845 BTC

tx

該筆交易的數據以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
    "hash": "0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2",
    "locktime": 0,
    "size": 258,
    "txid": "0627052b6f28912f2703066a912ea577f2ce4da4caa5a5fbd8a57286c345c2f2",
    "version": 1,
    "vin": [
        {
            "scriptSig": {
                "asm": "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
                "hex": "483045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf"
            },
            "sequence": 4294967295,
            "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
            "vout": 0
        }
    ],
    "vout": [
        {
            "n": 0,
            "scriptPubKey": {
                "addresses": [
                    "1GdK9UzpHBzqzX2A9JFP3Di4weBwqgmoQA"
                ],
                "asm": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a914ab68025513c3dbd2f7b92a94e0581f5d50f654e788ac",
                "reqSigs": 1,
                "type": "pubkeyhash"
            },
            "value": 0.015
        },
        {
            "n": 1,
            "scriptPubKey": {
                "addresses": [
                    "1Cdid9KFAaatwczBwBttQcwXYCpvK8h7FK"
                ],
                "asm": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
                "hex": "76a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac",
                "reqSigs": 1,
                "type": "pubkeyhash"
            },
            "value": 0.0845
        }
    ],
    "vsize": 258
}

交易輸入

1
2
3
4
5
6
7
8
9
10
11
"vin": [
    {
        "scriptSig": {
            "asm": "3045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e3813[ALL] 0484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf",
            "hex": "483045022100884d142d86652a3f47ba4746ec719bbfbd040a570b1deccbb6498c75c4ae24cb02204b9f039ff08df09cbe9f6addac960298cad530a863ea8f53982c09db8f6e381301410484ecc0d46f1918b30928fa0e4ed99f16a0fb4fde0735e7ade8416ab9fe423cc5412336376789d172787ec3457eee41c04f4938de5cc17b4a10fa336a8d752adf"
        },
        "sequence": 4294967295,
        "txid": "7957a35fe64f80d234d76d83a2a8f1a0d8149a41d81de548f0a65a8a999f6f18",
        "vout": 0
    }
]

它所包含的信息:

  • 交易ID。包含了它所指向的UTXO的交易的Hash值。
  • UTXO下標。定義了它所指向的UTXO在上一筆交易中交易輸出數組的位置(下標值)。
  • 簽名。用於知足它所指向的UTXO上所設定的花費條件。

交易輸出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
"vout": [
    {
        "n": 0,
        "scriptPubKey": {
            "addresses": [
                "1GdK9UzpHBzqzX2A9JFP3Di4weBwqgmoQA"
            ],
            "asm": "OP_DUP OP_HASH160 ab68025513c3dbd2f7b92a94e0581f5d50f654e7 OP_EQUALVERIFY OP_CHECKSIG",
            "hex": "76a914ab68025513c3dbd2f7b92a94e0581f5d50f654e788ac",
            "reqSigs": 1,
            "type": "pubkeyhash"
        },
        "value": 0.015
    },
    {
        "n": 1,
        "scriptPubKey": {
            "addresses": [
                "1Cdid9KFAaatwczBwBttQcwXYCpvK8h7FK"
            ],
            "asm": "OP_DUP OP_HASH160 7f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a8 OP_EQUALVERIFY OP_CHECKSIG",
            "hex": "76a9147f9b1a7fb68d60c536c2fd8aeaa53a8f3cc025a888ac",
            "reqSigs": 1,
            "type": "pubkeyhash"
        },
        "value": 0.0845
    }
]

它所包含的信息:

  • 比特幣的數量。單位:satoshis(聰)

  • 比特幣地址。交易輸出所綁定的地址。

  • 鎖定腳本。定義了花費這筆交易輸出所須要知足的限制條件。其中包含了一些字符串,例如:OP_DUPOP_HASH160OP_EQUALVERIFYOP_CHECKSIG,這些叫操做碼,後面會作介紹。

那麼,交易輸入中的script 是如何知足交易輸出中script_string的限制條件的呢?接下來,咱們來一塊兒看下比特幣的交易腳本是如何工做的。首先,咱們來了解一下比特幣所用到腳本語言的特性以及它的工做原理。

比特幣腳本語言

特性

腳本是一種相似Forth的基於堆棧的逆波蘭表示法的圖靈非完備語言。接下來,讓咱們逐個解釋一下:

圖靈非完備(Turing Incomplete

什麼是圖靈完備

可計算性理論裏,若是一系列操做數據的規則(如指令集編程語言細胞自動機)能夠用來模擬單帶圖靈機,那麼它是圖靈完備的。這個詞源於引入圖靈機概念的數學家艾倫·圖靈

雖然圖靈機會受到儲存能力的物理限制,圖靈徹底性一般指「具備無限存儲能力的通用物理機器或編程語言」。

來源:維基百科

https://en.wikipedia.org/wiki/Turing_completeness

圖靈非完備語言將會有有限的功能,不能進行跳轉或/和循環。所以它們不能進入無線循環。圖靈完備就意味着,在給定的計算資源和內存下,圖靈完備程序,可以解決任何問題。Solidity 就是其中一種圖靈完備語言。

爲何比特幣腳本是圖靈非完備的

由於沒有必要。比特幣腳本沒有必要作到像以太坊智能合約那樣複雜。事實上,若是一個腳本是圖靈完備的,它會給惡意的人以機會去隨意創造複雜的交易,這將會吃掉比特幣網絡的哈希率並下降整個系統的性能。

哈希率是比特幣網絡的處理能力的衡量單位。爲了安全,比特幣網絡必須進行高強度的數學運算。網絡的哈希率達到10TH/s,意味着這個網絡每秒能處理10億次計算。

逆波蘭表示法(Reverse Polish notation)

逆波蘭表示法Reverse Polish notationRPN,或逆波蘭記法),是一種是由波蘭數學家揚·武卡謝維奇1920年引入的數學表達式方式,在逆波蘭記法中,全部操做符置於操做數的後面,所以也被稱爲後綴表示法。逆波蘭記法不須要括號來標識操做符的優先級。

來源:維基百科

例如:

解釋 常規表示 逆波蘭表示法
三加四 3 + 4 34+
先3減去4,再加上5 3 - 4 + 5 3 4 - 5 +
先3減去4,再乘以5 (3 - 4)*5 3 4 - 5 *

基於堆棧

這是一種具備 LIFO(Last In First Out)特性的數據結構,熟悉數據結構的應該很是清楚,這裏很少作介紹。想深刻了解的朋友,能夠查看個人另外一篇文章:https://wangwei.one/posts/d1e0a844.html

stack

類Forth腳本語言

比特幣腳本剛好相似於編程語言「Forth」,它也剛好是基於堆棧的一種編程語言。

查看:Forth編程語言

工做原理

比特幣的腳本語言很是簡單,這種語言的代碼無非就是一系列數據和操做符。腳本語言經過從左至右地處理每一個項目的方式執行腳本。數字(常數)被推送至堆棧,操做符向堆棧推送(或移除)一個或多個參數,對它們進行處理,甚至可能會向堆棧推送一個結果。例如,OP_ADD將從堆棧移除兩個項目,將兩者相加,而後再將兩者相加之和推送到堆棧。

條件操做符評估一項條件,產生一個真或假的結果。例如,OP_EQUAL從堆棧移除兩個項目,假如兩者相等則推送真(表示爲1),假如兩者不等則推送爲假(表示爲0)。比特幣交易腳本常含條件操做符,當一筆交易有效時,就會產生True的結果。

咱們以一個簡單的腳原本進行演示:

1
2 3 OP_ADD 5 OP_EQUAL

從左至右,依次執行,過程以下:

弄明白這個過程以後,你會發現其中所蘊含的堆棧特性以及逆波蘭表示法特性。接下來,咱們來看下比特幣腳本的鎖定與解鎖邏輯。

鎖定與解鎖邏輯

比特幣的交易驗證引擎依賴於兩類腳原本驗證比特幣交易:一個鎖定腳本和一個解鎖腳本。

鎖定腳本是放置在輸出上的消費條件:它指定未來要花費輸出必須知足的條件。鎖定腳本常被稱爲scriptPubKey,由於它一般包含公鑰或比特幣地址(公鑰哈希)。

解鎖腳本是經過「解決」或知足鎖定腳本上的交易輸出條件並容許交易輸出花費的腳本。 解鎖腳本是每一個交易輸入的一部分。大多數狀況下,它包含了由用戶私鑰所產生的數字簽名。解鎖腳本常被稱爲 scriptSig ,由於它一般包含數字簽名。

每當要驗證一筆交易的有效性時,解鎖腳本和鎖定腳本會隨着堆棧的傳遞被分別執行。首先,使用堆棧執行引擎執行解鎖腳本。若是解鎖腳本在執行過程當中未報錯(例如:沒有「懸掛」操做碼),則複製 主堆棧(而不是備用堆棧),並執行鎖定腳本。若是從解鎖腳本中複製而來的堆棧數據執行鎖定腳本的結果 爲「TRUE」,那麼解鎖腳本就成功地知足了鎖定腳本所設置的條件,所以,該輸入是一個能使用該UTXO的有效授 權。若是在合併腳本後的結果不是」TRUE「之外的任何結果,輸入都是無效的,由於它不能知足UTXO中所設置的使 用該筆資金的條件。

下圖所示是最爲常見類型的比特幣交易(向公鑰哈希進行一筆支付)的解鎖和鎖定腳本樣ben,該樣ben展現了在腳本驗證以前將解鎖腳本和鎖定腳本串聯而成的組合腳本。

這是比特幣腳本中使用最爲常見的一種形式,名叫 Pay to Public Key Hash (P2PKH)。基於前面 2 + 3 = 5 的驗證過程,咱們能夠獲得 P2PKH 腳本在堆棧引擎中的驗證過程以下所示:

好了, 到此爲止,你已經對比特幣的交易腳本以及它的工做原理已經有了一個很是清楚的理解與認識。

參考資料

相關文章
相關標籤/搜索