区块链七-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 脚本在堆栈引擎中的验证过程以下所示:

好了, 到此为止,你已经对比特币的交易脚本以及它的工做原理已经有了一个很是清楚的理解与认识。

参考资料

相关文章
相关标签/搜索