比特币脚本简介
比特币有时也被称为可编程货币。它的数字性质,使得用户在设置如何使用资金的条件时拥有很大的灵活性
讨论比特币时,我们会提到钱包和代币。但我们也可以把钱包看作钥匙,把代币看作支票,把区块链看作一排又一排带锁的保险柜。每个保险柜都有一条细小的插槽,这样任何人都可以存入支票或查看保险柜里有多少价值。然而,只有钥匙持有人才能给保险柜开锁。
如果钥匙持有人想把钱给其他人,就会打开保险柜。他们会开一张引用旧支票的新支票(旧支票随后会被销毁),并将其重新锁在收款人可以打开的箱子中。为了花掉这笔钱,新的收款人需要重复这个过程。
在本文中,我们将更深入地了解脚本,这是一种由比特币网络上的节点进行解释的编程语言。脚本管理前面提到的保险柜的上锁/开锁机制。
比特币如何运作?
采用上述类比,可以说每笔交易都有两个部分 — 钥匙(用于给保险箱开锁)和锁。您需要用钥匙打开包含要发送的支票的箱子,然后将新的支票添加至另一个使用不同锁的新箱子。要花掉新箱子里面的钱,您需要另一把钥匙。
就这么简单。系统中的锁的类型可能会有一些变化。有些保险箱需要您提供多个多个钥匙,其他保险箱则需要您证明您知道某个密码,总之可以设定很多条件。
我们的钥匙就是我们所说的scriptSig,锁则是我们所说的scriptPubKey。如果我们更详细地观察这些组件,我们会发现它们实际上由数据位和代码块组成。当它们结合在一起时,就形成了一个小程序。
当您进行交易时,您就是在向网络广播该组合。每个接收到这笔交易的节点都将检查这个程序,该程序将告知节点这比交易是否有效。如果无效,交易就会被废弃,您将无法使用锁定的资金。
您持有的支票(代币)被称为未花费的交易输出(UTXO)。只要能提供与这把锁相配的钥匙,任何人都可以使用这笔资金。具体来说,钥匙是scriptSig,锁是scriptPubKey。
如果UTXO在您的钱包内,它们可能会有一个条件,即只有能证明该公钥所有权的人才能解锁这些资金。如需解锁资金,您需要提供一个包含数字签名的scriptSig,使用映射到scriptPubKey中指定公钥的私钥。一切很快就会变得清晰起来。
了解比特币堆栈
脚本是一种基于堆栈的语言。这就意味着,当我们阅读一组指令时,我们会将它们放在被认为是垂直的列中。例如,列表A、B、C将产生一个堆栈,A位于底部,C位于顶部。当指令告诉我们要做某件事时,我们就会从堆栈的顶部开始操作一个或多个元素。

元素A、B和C被添加并从堆栈中“弹出”。
我们可以区分数据(例如签名、哈希和公钥)和指令(或操作码)。指令删除数据并对其进行处理。以下就是一个非常简单的脚本示例:
<xyz> <md5 hasher> <d16fb36f0911f878998c136191af705e> <check if equal>
红色部分表示数据,蓝色部分表示操作码。我们从左到右读取,因此我们首先把字符串<xyz>放到堆栈上。接下来是<md5 hasher>操作码。这个操作码在比特币中并不存在,但我们假设它删除了堆栈顶部的元素(<xyz>),并使用MD5算法进行了哈希。随后将输出添加回堆栈。这里的输出恰好是d16fb36f0911f878998c136191af705e。
太巧了!我们要添加的下一个元素是<d16fb36f0911f878998c136191af705e>,因此,现在我们的堆栈有两个相同的元素。最后,<check if equal>在顶部弹出两个元素,并检查它们是否相等。如果相等,则将<1>添加至堆栈。如果不相等,则将<0>添加至堆栈。
我们已经到了指令列表的末尾。我们的脚本可能会以两种方式失败 — 如果剩余元素是零,或如果某些条件不满足时,其中一个运算符将导致其失败。在这个例子中,我们没有任何这样的运算符,最终得到一个非0元素(<1>),因此我们的脚本是有效的。这些规则也适用于真正的比特币交易。
上述示例只是一个虚构的程序。现在我们来看一些实际的示例。
支付到公钥(P2PK)
支付到公钥(P2PK)非常简单。它设计将资金锁定至特定的公钥。如果您想以这种方式接收资金,就需要向发送者提供您的公钥,而不是比特币地址。
中本聪和Hal Finney在2009年的第一笔交易就是P2PK交易。这种结构在比特币早期被大量使用,但如今,支付到公钥哈希(P2PKH)已经在很大程度上取代了它。
P2PK交易的锁定脚本遵循<public key> OP_CHECKSIG的格式。就这么简单。您可能已经猜到,OP_CHECKSIG会根据提供的公钥检查签名。因此,我们的scriptSig将是一个简单的<signature>。记住,scriptSig是开锁的钥匙。

没有比这更简单的了。签名被添加到堆栈中,随后是公钥。OP_CHECKSIG同时弹出签名和公钥,并根据公钥验证签名。如果二者匹配,则向堆栈中添加<1>。否则添加<0>。
出于我们即将在下一节详细说明的原因,P2PK实际上已经不再使用。
支付到公钥哈希(P2PKH)
支付到公钥哈希(P2PKH)是现在最常见的交易类型。除非您特地去下载过时的软件,否则您的钱包很可能会默认采取这种交易。
P2PKH的scriptPubKey如下:
OP_DUP OP_HASH160 <public key hash> OP_EQUALVERIFY OP_CHECKSIG
在我们介绍scriptSig之前,我们首先来分析一下新的操作码的作用:
OP_DUP
OP_DUP弹出第一个元素,并复制这个元素。随后,它将二者同时添加回堆栈。通常,这样做是为了在不影响原始元素的情况下对副本进行操作。
OP_HASH160
这将弹出第一个元素,并进行两次哈希。第一轮将使用SHA-256算法进行哈希。随后使用RIPEMD-160算法对SHA-256输出进行哈希。结果输出被添加回堆栈。
OP_EQUALVERIFY
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),才能得到私钥。