29

深度好文: 如何在BCH上实现ETH式的智能合约?

 5 years ago
source link: https://www.tuicool.com/articles/Mju2QfY
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

文| Bruce Lee(转载请注明出处)

微信公众号: BCH爱好者BruceLee

微博: BCH爱好者BruceLee

众所周知,因为BCH脚本的限制(其他特比特系分支也一样),开发者只能在BCH主链上实现无状态的智能合约,这就使得BCH智能合约可以做的事情变得很有限。但是近期BCH的资深开发者Chris Pacia发现,BCH可以通过升级实现有状态的智能合约,就像ETH那样。

------以下是译文-----

Malfix是BCH的一个涉及到共识变更的提案,旨在解决交易延展性BUG。这是一个相当有争议性的提案,部分原因是它将成为BCH最重大的硬分叉变化,还有个原因是很多人认为这是不必要的。在本文中,我会介绍一个我们以前从来没考虑过的Malfix的用例 – 给予BCH以太坊式的完整的智能合约编程能力。

乍看之下,这有点疯狂。一个用来修复交易延展性BUG的的提案,怎么可能会让BCH成为以太坊的竞争对手?让我们深入研究下去吧。

以太坊(ETH)

ETH的核心功能是可以让用户在链上创建合约。有了这些合约,用户就可以保存数据。合约定义了许多功能,当用户通过一个新的交易连接到合约时,用户可以读取数据,以某种方式操作它,并且将其保存到合约里面。

这是在区块链上保存数据的核心功能(我们现在开始称其为“状态”),比特币一直缺乏这种向合约读写数据的能力。在比特币中,我们有一种脚本语言,但是它仅能允许我们从一个地址释放币时设置一些条件。绝大多数人会告诉你,这些脚本无法把状态保存到区块链上,并且脚本也无法像ETH那样从任何其他交易中读取状态。

或许,他们其实是可以的?

OP_CHECKDATASIG

2018年11月,BCH新增了一个操作码OP_CHECKDATASIG,当时BSV粉想尽办法阻止这个操作码添加到协议里面,但是最终失败了。

这个操作码看上去非常基础,它所能做的事情只是接受任意签名,公钥和消息,并且验证签名。

<signature><public_key> <message> OP_CHECKDATASIG

这个类型的功能对于加密货币非常重要,但是它竟然没有在一开始就包含在比特币里面,这令人相当惊讶。

虽然这个操作码看上去相当缺乏想象力,但它实际上非常有用,每天我们都从中学习到越来越强大的能力。

合约

OP_CHECKDATASIG启用的第一个主要功能是一个叫做合约的东西。在OP_CHECKDATASIG出现之前,比特币脚本只能在释放币的时候设置一些条件,仅此而已。举个例子,某个脚本可以说“如果A向这个脚本提供一个有效输入,那么他就可以解锁并花费这个地址上的币。但是一旦币被解锁,他就可以把币发送到任意地址。”

而合约可以限制A只能把币发送到某个地址。OP_CHECKDATASIG 如何实现这个限制呢?请思考以下脚本

<signature> <public_key> OP_CHECKSIG

这是一个典型的比特币交易的花费脚本。OP_CHECKSIG操作码对交易数据进行哈希,并且检查签名相对于给定的公钥和交易哈希值是否有效。

现在假设我们使用和上述完全相同的签名和公钥,如果通过OP_CHECKDATASIG操作码进行哈希运算和校验。

<signature> <public_key> <message> OP_CHECKDATASIG

如果这个消息(message)和这个交易的原始交易数据一致,那么脚本运行结果为真(true)。由于OP_CHECKDATASIG会对这个消息进行哈希,并且根据公钥和哈希值进行签名验证,如果相同的签名和公钥都通过了OP_CHECKSIG和OP_CHECKDATASIG的检查,那么我们就知道堆栈上留下的消息就必定是这个交易的原始数据。

这非常聪明。我们现在已经获得了原始数据的访问权限,并且可以使用脚本对其进行解析,确保交易中的输出把币发送到我们希望送达的地址。换句话说,我们可以使用脚本语言限制某个交易只能把币发送到某个特定的地址。

那我们可以用来做什么呢?我们可以做很多有趣的事情。举个例子,有个叫last will的智能合约使用热私钥和冷私钥实现了一个死人开关(注: dead manswitch,不知道如何翻译恰当),让偷币变得极其困难。

我们还可以创建循环交易。请注意,比特币脚本自身是无法循环的,它就是这么设计的。但是我们可以在脚本上放一个合约,强制币返回到它发出的地址。基本上,一旦币进入了那个地址,它就会永远在那里,并且没法出来。我将这种脚本称为“循环”,因为每当有人从此地址开始花费,相同的脚本就会再次执行。只要一直有人愿意发出交易(当然这是需要支付手续费的),这个脚本就会一直运行。

但是这看上去似乎毫无用处,我们为什么要这么做?

创建ETH式的智能合约

一旦堆栈上有原始交易数据,我们就可以做更多事情。我们可以把前一个交易压入堆栈,通过对前一个交易进行哈希,并且比对当前交易的输出端的哈希值,我们就可以验证这是否是前一个交易。

但是等一下,还有更多!

通常,当脚本执行任何脚本自身一部分计算的数据时,所有意图和目的都会丢失。计算结果(如果有的话)不会保存在区块链中的任何地方,当然也不能被其他交易访问。但是,使用合约,我们可以把计算结果保存在交易的OP_RETURN输出中。这要求资金的花费者在他的本地计算机上运行大部分脚本,以确定计算结果。计算完成后,合约会将结果保存在OP_RETURN里面。

现在请注意我们拥有了什么?这个脚本运行并且完成了一大堆计算,计算结果保存在交易里面,并且这笔交易数据可以被下一笔交易访问。换句话说,现在比特币脚本可以以这样的方式在区块链中保存状态,以后的交易可以读取这个状态,执行某些计算并且以某种方式改变它,并将其保存到区块链上。基本上,我们在BCH上实现了ETH的功能!

比特币命名系统

这只是一个例子。ETH上有一个叫ENS的东西 – 以太坊命名系统(Ethereum Naming System)。这是一个智能合约,允许人们在链上注册名字(或域名),并且映射到特定的数据,比如IP地址,或者ETH钱包地址。

使用上面的方案,我设计了一个叫BNS(比特币命名系统)的智能合约,基本上做和ENS一样的事情,是如前文所说的那种任何人都可以花费的循环合约。当有人想注册名称时,他们会把当前交易,先前交易,要注册的名称,和一个merklix排除证明压入堆栈。合约会从前一个交易载入合约状态树的根哈希,验证先前所说的merklix根的排除证明,证明之前没有人注册过该名称,然后更新根哈希并在交易中保存新的状态。就像以太坊上的ENS智能合约一样,BNS管理名称的状态数据库并防止双重注册。名称可以转换为SLP token,并且用来交易。

几乎完成了

在遇到大问题之前,我们已经把这个方法完成了99%。当你把数据压入堆栈,BCH的共识规则要求数据体积必须小于520字节。当你把上一个交易压入堆栈,如果数据大于520字节,交易就会失败。

可以想象单个交易的体积可以在520字节以下,但是这个体积会随着新的交易不断增长。看下这个:

交易B把前一个交易A压入堆栈。

交易C把包含交易A的交易B压入堆栈。

交易D把包含交易A&B的交易C压入堆栈。

。。。

在1,2次交易之后,我们就超过了520字节的限制。我们已经和ETH式的智能合约如此接近了,但是因为空间不足,我们失败了。

Malfix

Malfix引入了新的交易版本V3。这种版本的交易具有两个交易ID。一个是普通的大家所熟知的TXID;另外一个是UTXID,是去除了输入脚本的交易的哈希值。在大多数地方,你可以像以往那样使用TXID。唯一的区别是,在交易的输入端的前一个输出端引入V3版本的交易时,你应该使用UTXID代替。

这个起到的作用是,当我们把上一个交易压入堆栈时,我们就不需要把输入脚本压入堆栈。这将使我们的数据永远保持在520字节以下(他们不会再像之前那样随着每个交易增长)

这个相对较小的变化就是我们所需要的全部。

Malfix 的问题

从全节点的角度来看,Malfix实现起来相对简单。它的主要是问题是不像之前每次BCH的硬分叉升级,这个相当具有侵略性。所有的钱包都需要升级,才能处理V3版本的交易。

如果一个未升级的钱包收到了一笔V3版本的交易,它就不能花费里面的币。

我们可以通过以比特币现金地址格式碰撞版本字节(或保留位)来缓解这种情况。

已升级的钱包可以编程为: 当发送币到旧版本字节时,只能构造V1或V2版本的交易(可选);当发送币到新版本字节时,就使用V3版本的交易。这主要是为了防止未升级的钱包接收V3版本的交易,并且允许它们按照自己的节奏升级。

可能有其他类型的服务会因为Malfix而中断,我们必须长时间的深入思考可能会是哪些服务以及如何简化升级。

与以太坊的比较

所以这是否意味着BCH具有ETH的全部功能了呢?并不完全是的。记住,ETH是从一开始就设计成按照这种方式运行的。比特币在设计时显然没有考虑到这种类型的功能,我们只能使用更加聪明的方式来打破比特币的天然限制。我认为ETH这样的智能合约总是更加容易进行开发,尽管像Spden这样的高级语言在某种程度上也可以帮助BCH开发者体验智能合约。

BCH保存状态的方式和ETH也是不同的。在ETH里面,只要你愿意支付gas,你可以在合约中保存任何类型的数据。

在BCH里面,我们最多只能在op_return里面保存220字节数据,这只够用来保存一些哈希值。这意味着我们的状态需要成为数据树的根,而不是数据本身,就像之前BNS(比特币命名系统)那个例子。使用合约的人将自己负责存储实际数据(尽管可以通过扫描合约的所有交易来重建状态)

最后一点,ETH上的合约可以对其他ETH合约进行函数调用。我不确定这在BCH上是否可行,因为我还没有深入思考过。

如果Malfix提案最终可以通过,那么在BCH上创建ETH式的智能合约是切实可行的。我们或许无法实现ETH的所有功能,但这依旧是一次脚本语言的大规模升级。

原文作者: Chris Pacia (BCHD全节点开发者)

原文链接:

https://honest.cash/cpacia/a-case-for-malfix-4436/

------译文结束-----

结束语

我是怀着非常激动的心情看完这篇文章的,并且前后看了好多遍。我觉得非常有必要让国内BCH社区了解这个具有革命性意义的技术,因此特意花几个小时翻译了这篇文章。文中难免有些错漏之处,请谅解。

智能合约的重要性不言而喻,像前几天上线的比特耶稣的那个OTC平台,核心功能就是一个利用OP_CHECKDATASIG操作码构建的智能合约。

Malfix这个提案如果真的实现,BCH能做的事情就会变得非常非常多。按照我的理解,在BCH上实现这种ETH式的智能合约,不会出现像目前ETH那样的性能瓶颈。而且这是BCH主链上的智能合约,因此这些合约都是可以支持0确认交易的,到时候BCH就会变得极其具有竞争力。画面太美,简直都不敢想啊。希望11月份的升级可以通过这个提案。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK