# Hardcore | Miniscript：让比特币编程更便捷高效的“神器”

By [NonFungibleRay](https://paragraph.com/@nonfungibleray) · 2021-12-30

---

比特币为世界带来了首个智能合约开发语言——**Script**，其能够让不同的加密货币在不同的编程环境下被使用。然而这一概念在极具颠覆性的同时，使用起来却有一定难度，特别是在较为复杂的花费环境下。**无论是编写较为复杂的智能合约，还是验证合约是否正确运行其职能，都很容易出现人为错误（漏洞）**，在关系到资产安全的情况下，对于脚本程序运行条件正确性的验证变得尤为重要.

在过去的一年中，区块链工程师Andrew Poelstra, Pieter Wuille（比特币核心开发人员、同时也是隔离见证机制SegWit创建者）和Sanket Kanjalkar开始着手改进这一点。通过将Script语言拆分简化，保留其最基本的要素和功能，优化出了“新”的编程语言——“Miniscript”——减少了原编程语言的复杂性，让所有进行比特币编程的人们获得更安全、便捷的体验。

> “从理论上来讲Miniscript相比Script有了更多的明确的使用条件和限制，但实际上人们可以用它完成任何Script所能做的事情。”Blockstream研发主管以及Miniscript联合设计者Andrew Poelstra表示。

![](https://storage.googleapis.com/papyrus_images/72126769277cde4157e927cd065e38191514978ba265c79d645f32695b197b37.png)

**SCRIPT**

我们首先来简单了解一下Script（脚本）语言。

每一笔比特币交易都包含两个主要部分：**输入(input)和输出(output)**，二者都有自己的代码，输入(inputs)“解锁”了代币，而输出(outputs)将代币再次“锁住”，并规定了下一次被解锁再次进行交易输入的条件，在这些条件中通常包括一个有效的加密签名，更多的可能条件例如:该（比特）币必须经过一定的时间后，或必须含有特殊的密码才能被使用或花费。

交易中的这段代码就是用Script创建的，Script是专门为比特币设计的编程语言。其灵感来自于Forth，一种20世纪60年代发明的编程语言，最初设计用来操作射电望远镜。不过，Script在经过调整之后更加契合比特币。

例如，Script中没有使“循环”的操作码(指令):该语言不支持无限次执行相同的计算。因为在比特币中，没有必要无限次地执行相同的计算，因为比特币的节点们实际上并不通过计算进行交易——而是验证交易。(关于为什么会出现这种情况，Blockstream工程师罗素·奥康纳(Russell O 'Connor)在三年前就发布了文章:[**_对比特币和以太坊的脚本语言和理念进行比_较**](https://old.reddit.com/r/Bitcoin/comments/4pdx6k/comparison_between_bitcoin_and_ethereums/)，其中进行了较为详细的解释。）

同时Script并没有被“类化”，这意味着计算的结果可以以不同的方式被注释和使用，举个很简单的例子，**一个有效签名的结果可能是“true”**,而\*\*“true”可以被注释转化等于数字“1”**进而用于**数学程式**中，true=1，而**true+true**则可以被看成**1+1=2\*\*，意味着如果交易最少需要两个有效签名进行验证，则其满足了这个条件。

这其实为我们引入了Script语言中最重要的一个属性——“**难以推理**(参考Preethi Kasireddy关于JavaScript提出的文章\*\*\*[当我们说一段代码”易于推理”到底是什么意思?](https://www.freecodecamp.org/news/what-does-it-mean-when-code-is-easy-to-reason-about-4e6f63eb386f/)**_)” 这基本意味着_**_Script的计算结果能够以多种方式被注释转化，即使一个签名是无效的，在Script中其仍可以出于某些原因将其编写为有效。_\*

> “在Bitcoin Script中的确有一些运算码在运行时闹出荒唐事，例如，将一个签名解释为真/假值，在此之后将该布尔值转化为数字（例如1/0）后编入堆栈索引中，再根据这一数值将堆栈重新排列，然而在实际运行过程中其具体规则是非常荒唐可笑的。”Poelstra解释道。

这样一来在通过Script处理一些问题时会很棘手，尤其是在花费（“已解锁”）代币的要求变得更加复杂时，一笔交易的发起者的代码中可能会**无意中包含了允许代币在其他条件下被使用的信息**，反过来也就是说，交易的**收款方有可能因为没有注意到这样的“漏洞”而被发现这样信息的攻击者攻击受到损失**。

总结来说,当前Bitcoin Script的最大问题是**在对较为复杂的程序进行验证时比较困难(容易出错)**.

**问题的具体举例**

关于以上的问题如何限制了Script的实用性，下面我们举一个具体一些的例子。

Blockstream Green Wallet钱包有一个标准的“共同签名”设置，钱包用户掌控2个密钥中的一个，Blockstream掌控另一个，这样一来钱包中的数字资产能够通过两种方式被使用。**用户想要使用资产**：用户签署了该笔交易并请求Blockstream一并签署，通常Blockstream都会通过执行（经过邮箱或短信验证码二次确认后）；**但可能发生的一种情况是**：Blockstream这一端出现了问题——如公司跑路或者丢失了密钥，或出于其他原因无法签署。在这样的情况下，用户需要使用一个**备用方案**来完成这笔交易：如在锁定时间过后，用户可以在预定时间过后（例如一个月）完成该笔交易（使用资产）。

这样的解决方案似乎可行，但仍会受到限制，比如**用户将无法再使用任何其他比特币的潜在智能合约，或在其终端增加更多灵活可扩展的设置**。

> “现在Green有一个适用于所有客户的预备脚本，基本上就是一个简单的多重签名，但是我们并不真正在乎脚本讲了什么，我们在乎的是，在规定时间内，交易代币是否有可能在不需要我们（Blockstream）签名的情况下被交易？如果用户提出一些与常人不同的要求，但只要原则上这些要求是我们关心和在乎的，我们就应该满足和支持。”

举个例子，一些用户以防有什么意外发生，希望让他的另一半或家人在一年后能够（有权）继承使用这笔资产；或以用户是一家公司为例，其希望创建一个使用机制，例如需要三分之二或更多的董事会成员权限才能共同使用资产。

当然从技术上来讲，在比特币脚本语言（Bitcoin Script）中以上的情况都是可以被实现的，但这将需要用户设计一个自定义程序，而Blockstream（资产托管方）也需要确保参与其中。

这样就太复杂了，“如果用户任意提供给我们一个脚本语言，我们几乎无法确定其是否满足了我们所关心在乎的那个运行条件，因为所有脚本行为的组合非常复杂，举个例子，假如用户提供的一个脚本程序看上去需要一个签名(signature)进行认证，但我们还需要考虑，如果用户提供了一个non-signiture会发生什么情况？其是否会触发其他条件使资产能够被调用？等等。”Poelstra解释道。

**Miniscript**

在过去的一年中，Poelstra、Blockstream 核心技术工程师Pieter Wuille和Sanket Kanjalkar设计了Miniscript（Miniscript官方并不属于Blockstream的产品）。

**简而言之，Miniscript是一个“删减版”的Script**：从Script工具包（Script toolkit）中整合选择了更加易用和易于被验证的工具，而除去极少数基本无人使用的工具外，**几乎所有Script能干的事Miniscript也能干。本质上来讲，一行Miniscript的代码仍可以看作等于一行有效地Script代码，只不过Miniscript通过防止代码出现意料之外（无意的）结果而尽可能的减少Bug的出现。**

就拿我们上面提到过的问题来说，用户可以利用Miniscript更加容易地设计出一个便于Blockstream验证其是否满足运行条件的设置，详细来讲，Blockstream能够更加清晰地明白用户资产的被使用条件（如，要么签名通过，要么时间到了），不管用户在其自定义程序端还夹杂了任何其他附加条件，如额外的时间要求、多重签名等，说白了，使用了Miniscript，在Blockstream端来看可以免去那些“花里胡哨”的，可能影响验证条件或“偷换概念”的东西，更干净利落。

Miniscript语言非常直接且可预测，其程序总能导向一个决策树，将程序很清楚的呈现出来（就像图像编码），易于推理。

![](https://storage.googleapis.com/papyrus_images/91efb52ea64b68c21441f5c04671f509a68768c073451f20632798ce03df2272.png)

就在上周，Pieter Wuille在Medium发文再次介绍了Miniscript\*\*（[_Miniscript: 改进后的比特币脚本语言_](https://medium.com/blockstream/miniscript-bitcoin-scripting-3aeff3853620)）\*\*，他拿一段在比特币脚本语言中的代码为例: 

> OP\_CHECKSIG OP\_IFDUP OP\_NOTIF OP\_DUP OP\_HASH160 <hash160(B)> OP\_EQUALVERIFY OP\_CHECKSIGVERIFY <144> OP\_CSV OP\_ENDIF
> 
>  其中，A和B为公钥，在Miniscript中这段语言可以被精简为：
> 
> > or\_d(c:pk(A),and\_v(vc:pk\_h(B),older(144)))
> 
> 这段代码很清楚明了地表现了代币的解锁条件：**A签名通过；或者经过144个区块后B签名通过**。而很大一部分的Script可以以这样的方式编写。
> 
> **策略语言和投入使用**
> 
> 尽管Miniscript也还在继续开发中，但其早期版本已经发布并可以投入使用了。
> 
> 甚至为了让编写Miniscript变得更加简单，Wuille还设计了一种“**策略语言**”，策略语言更像是用户编写自己熟悉的语言，其最终可以**被编译（转换）至Miniscript格式，进而可以被用于Script，并入比特币交易输出中。**
> 
> 这种策略语言的最大好处就是，它会在**根据脚本编写的不同情况下，尽可能地自动地转换至最合适、高效的Miniscript格式。**
> 
> “在Script里你可以有非常多的编写方式表达‘**或（or）**’；有非常多的编写方式表达‘**和（and）**’，但当然其中总有一些表达方法是更高效的，而**策略语言中‘或（or）’、‘和and’和其他条件的表达方式是固定的**，Pieter Wuille还设计编写了一个超极简单明了的**编译器(compiler)**,让策略语言能够以最优的方式转化至Miniscript格式。”
> 
> 根据其\*\*\*[线上编译器](http://bitcoin.sipa.be/miniscript/)\*\*\*，刚刚我们举例编码在策略语言中可以再次被转化为：
> 
> > or(99@pk(A),1@and(pk(B),older(144)))
> 
>  这样的写法意思是：左边的 “**或(or)”被采用的概率是99%（A签名通过）**;右边情况“**和(and)**”**（经过144个区块后B签名通过）发生概率为1%**。
> 
> ![](https://storage.googleapis.com/papyrus_images/75dec918983fd9a96988464bebdd3a37b4e7c8cd167298690cab43a1d0b7652d.png)
> 
> （编译表的主要对照部分，[http://bitcoin.sipa.be/miniscript/](http://bitcoin.sipa.be/miniscript/)）
> 
> 值得注意的是，**以上并不仅仅是一个理论概念**，虽然当前的Miniscript和编译器(Compiler)都不是最终版本，但Blockstream内部已经正在将其使用于Liquid官方侧链软件（Liquid sidechain）的分支开发中了，其中一个功能被称为**Dynamic Federations（动态联盟）**，其允许现有的Liquid成员对新加入的成员进行管理，或对现有在联盟控制下的比特币使用权限的脚本进行更新。Miniscript为构建和更新此类相关的Script提供了更高效快速的工具，\*\*经过现有的Miniscript编译器转化后，原有的已经经过人工精简和优化过的Liquid Script脚本被再次精简了22个字节，\*\*相比原有的脚本约节省了5%的工作量。**更重要的是**，其允许成员对新提出的脚本更改的主体部分（**成员密钥、代币紧急被调用的条件正确性以及联盟新成员对原联盟控制资产的使用条件等**）进行自动化验证，减少了成员间相互协调、对脚本进行复杂的人工安全审计的必要。
> 
> 目前Miniscript的策略语言编译器可以支持C++和Rust语言的转化，为了让这项技术更易于使用，Pieter表示未来他们还需将它与其他常用软件整合集成，通过实现对**相位整形二进制传输（双二进制,PSBT）和Miniscript的兼容（更新器updater和终结器finalizer等）**，许多PSBT签名使用者（包括硬件钱包）即使没有显式支持的情况下，也可被用于复杂的脚本中；此外，由于许多策略语言的脚本转换结果还没有被考虑到，编译器也将会被进一步优化改进。
> 
> 本文编译参考资料及原文: 
> 
> [_Miniscript: How Blockstream Engineers Are Making Bitcoin Programming Easy(er)_](https://bitcoinmagazine.com/articles/miniscript-how-blockstream-engineers-are-making-bitcoin-programming-easyer)   _By: Aaron Van Wirdum_
> 
> [_Comparison between Bitcoin and Ethereum's philosophy and scripting language (& OP\_EVAL) by Purse.io's CTO, JJ_](https://old.reddit.com/r/Bitcoin/comments/4pdx6k/comparison_between_bitcoin_and_ethereums/)
> 
> [_What does it mean when code is “easy to reason about”?_](https://www.freecodecamp.org/news/what-does-it-mean-when-code-is-easy-to-reason-about-4e6f63eb386f/)  _By: Preethi Kasireddy_
> 
> [_Miniscript: Streamlined Bitcoin Scripting   By: Pieter Wuille & Andrew Poelstra_](https://medium.com/blockstream/miniscript-bitcoin-scripting-3aeff3853620)

---

*Originally published on [NonFungibleRay](https://paragraph.com/@nonfungibleray/hardcore-miniscript)*
