【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

量子链基于经典的权益证明机制(Classic Proof of Stake)作为共识机制,和比特币和以太坊的工作量证明机制是不同的,是整个区块链行业首个POS机制下的智能合约平台,也是首个通过EVM支持比特币生态的智能合约平台。
近日量子链Qtum 团队发布了开发总结和开发进展,并完成了首个基于比特币UTXO模型的POS智能合约平台,也成为继以太坊之外,第二个全面支持图灵完备的智能合约的区块链平台。想要在基于比特币UTXO模型的量子链的账户抽象层中实现,是否比想象中更复杂,更困难呢,本文详解Qtum做了哪些借鉴和修改之处而达事半功倍的。
注:本文部分内容,来自Qtum量子链技术白皮书

以太坊虚拟机(EVM)使用了256比特长度的机器码,是一种基于堆栈的虚拟机,用于执行以太坊智能合约。由于EVM是针对以太坊体系设计的,因此使用了以太坊账户模型(Account Model)进行价值传输。而量子链的设计是基于比特币UTXO模型,所以在量子链模型设计中加入了账户抽象层(Account Abstraction Layer),用于将UTXO模型转换成可供EVM执行的账户模型。此外,Qtum还加入了区块链接口(Blockchain Interface),使EVM可以直接读取量子链上的信息。


1.EVM集成

通过拓展比特币网络的脚本语言,量子链的开发中加入了三个全新的操作符:

1. OP_EXEC – 用于执行EVM传输的脚本代码,且可以触发交易过程中的一个特殊进程(后续会详细介绍);

2. OP_EXEC_ASSIGN – 用于传递调用智能合约所需要的相关数据(即EVM中的CALLERDATA)和地址信息,并执行合约中的代码内容。该操作符还可为智能合约发送资金。与OP_EXEC类似,也可以触发特殊进程;

3. OP_TXHASH – 将当前合约的ID哈希值压入栈内,还可对账户抽象层中的异常数据进行重新核算。

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

图1:Qtum系统的交易传输架构模型

在比特币系统中,只有当解锁脚本(ScriptSig)与锁定脚本(ScriptPubKey)验证通过后才能花费相对应的交易输出。举例来说,锁定脚本通常会把一个交易输出锁定到一个比特币地址上(公钥的哈希值),只有当解锁脚本和锁定脚本的设定条件相符时,执行组合脚本才会显示结果为真(系统返回值为1),这样相对应的交易输出才会被花费。

而在Qtum系统中,我们更强调智能合约执行的及时性。因此我们在锁定脚本中加入了OP_EXEC和OP_EXEC_ASSIGN操作符。当Qtum系统检测到该操作符时,全网节点就会执行该交易。这样一来,比特币脚本扮演的角色,更多的是将相关数据传送至EVM,而不仅仅作为一种编码语言。与以太坊执行智能合约一样,由OP_EXEC和OP_EXEC_ASSIGN操作符触发的合约,EVM会在各自的状态数据库中更改其状态。

考虑到量子链智能合约的易用性,需要对触发智能合约的数据以及数据来源的公钥哈希值进行验证。

为了防止量子链上UTXO所占比例过大,开发团队将OP_EXEC和OP_EXEC_ASSIGN的交易输出也设计成可花费的。OP_EXEC的输出可以用作合约自毁操作,OP_EXEC_ASSIGN的输出可以为其他合约或公钥哈希地址发送资金。


2.Qtum账户抽象层(Qtum AAL)

在以太坊是基于账户的区块链系统。而Qtum是以比特币UTXO模型为基础的。为了解决两者交易模型的差异问题,在量子链模型设计中加入了账户抽象层(Account Abstraction Layer),这样可以最大程度上保持原有EVM的功能并兼容现有以太坊的智能合约。

对于智能合约的开发者来说,EVM的账户模型相对简单。它支持合约余额的查询,还可为其他合约发送资金等操作。尽管这些操作看起来十分的简单和基本,但是想要在基于比特币UTXO模型的量子链的账户抽象层中实现,比想象中更复杂,更困难。

首先,对于在Qtum上创建的智能合约,系统会生成一个交易哈希值用于合约的调用。新合约的初始余额为0(目前不支持非0初始余额的合约)。为了满足合约发送资金的需求,Qtum使用OP_EXEC_ASSIGN操作符来创建交易输出。

合约发送资金的输出脚本类似于:

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

这个脚本并不是特别复杂,并且OP_EXEC_ASSIGN完成了大部分所需的工作。Qtum定义交易的具体花费(不考虑out-of-gas的情况)为OutputValue,即GasLimit。具体的Gas机制会在后续章节中谈及。当上述输出脚本添加到区块链上时,该输出就与合约的账户建立了对应关系,并且体现在合约的余额中。余额可以理解为可供合约花费的总和。

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

图2 合约交易流程

图2中介绍了通过标准公钥哈希地址输出用于合约交易的基本流程,合约之间的交易流程也大体一致。此外,还可以通过P2SH和非标准交易(non-standard transactions)进行交易。

当前合约需要与另外一个合约或公钥哈希地址进行交易时,该合约账户中可供使用的输出将会被消耗。这部分被消耗的输出在Qtum网络中用作交易验证,必须存在,我们称之为合约预期交易(Expected Contract Transactions)。由于合约预期交易是在矿工验证和执行交易时产生的,而不是由交易用户产生,因此不会通过全网进行广播。

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

图三:Qtum Block Validation showing Expected Contract Transaction List

合约预期交易的主要工作原理是通过OP_TXHASH代码实现的。OP_EXEC和OP_EXEC_ASSIGN有两种工作模式,当操作符作为输出脚本时,由EVM执行;当操作符作为输入脚本时,EVM不会被执行(否则会导致重复执行),这种情况下OP_EXEC和OP_EXEC_ASSIGN可当作无指令操作。OP_EXEC和OP_EXEC_ASSIGN接收由OP_TXHASH传递的交易哈希值,并返回1或0(即可花费或不可花费)。这里就体现出OP_TXHASH在整个合约预期交易的重要性。具体解释,当OP_TXHASH将交易哈希值传递给OP_EXEC和OP_EXEC_ASSIGN,由OP_EXEC和OP_EXEC_ASSIGN比对该哈希值是否存在于合约预期交易列表中。若在,则返回1,即可花费的;否则返回0,即不可花费的。这个逻辑间接提供了完整安全的方式来保证合约的资金只能由该合约使用,与普通UTXO交易输出一致。

目前还有一个问题尚未解决:当合约中有多个可花费输出时,不同的节点可以选择不同的输出,这就导致了花费不同的OP_EXEC_ASSIGN交易。同时,为了避免DoS(拒绝服务)攻击和尽可能的简化共识原则,Qtum将标准coin picking算法进行了适当简化,命名为Consensus-critical

coin picking算法。这样,全网节点只能选择合约中的同一个可花费输出,不同选择将会导致所在节点与Qtum主链的分叉,分叉上的区块将被认为无效区块。

综上所述,当EVM合约向公钥哈希地址或另一个合约发送资金时,将会建立一个新的交易。使用Consensus-critical coin

picking算法,可以在合约可供使用输出池中选择最合适的交易输出。选中的交易输出将会作为执行单个OP_TXHASH的输入脚本,而输出则是资金的目的地址,并将剩余资金发送回合约,同时更改可供消耗的输出。然后,这个交易的哈希值将会添加在合约预期交易列表中。当交易执行后,该交易会被立即添加到区块上。当链上的矿工验证并执行该交易后,合约预期交易列表将会被重新遍历,验证正确无误后,将此哈希值从表中删除。这样,使用OP_TXHASH可以有效的防止使用硬编码哈希值来更改输出的可花费性。

Qtum账户抽象层使EVM无需过度关注coin-picking,只需要了解合约中的余额,并可以与其他合约甚至公钥哈希地址进行资金往来。这样,仅需对以太坊智能合约做稍许修改即可满足Qtum的合约运行需求。

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

图4:Spend contract OP_EXEC_ASSIGN transaction


3.新增标准交易类型

Qtum中新增了标准交易类型,用比特币脚本模板表示,在区块链上创建新合约的脚本为:

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

向合约发送资金的脚本为:

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

值得注意的是,目前标准的交易类型并不能消耗上述交易输出。只有当交易输出哈希值在合约预期交易列表上时,才可被消耗,而且该消耗不会在P2P网络进行全网广播。


4.Gas模型

当Qtum开发团队试图把图灵完备语言加入到比特币区块链上时,意识到并不能仅根据交易的大小来决定支付给矿工的费用。因为一个很小的交易也可能包含无穷循环,从而导致整个区块链系统的崩溃。因此,Qtum借鉴了以太坊中gas的概念,在EVM上执行代码、进行交易都需要消耗一定数量的gas。若执行结束后还有gas剩余,这些gas将被返还给发送用户。在代码的执行过程中,一旦gas被耗尽,将会触发out-of-gas异常,则当前调用帧所做的所有状态修改(包括永久内存,合约资金)都将被回滚,但是消耗的gas不会被回滚,因为回滚操作也占用了全网的算力和矿工时间。

尽管Qtum借鉴了以太坊中的gas模型,但二者的gas schedule (即执行EVM代码的gas花费)仍截然不同。这是由于有的操作在Qtum的EVM执行比以太坊要耗费更多的gas,有的操作则相反。因此,Qtum将根据现有的以太坊gas价格并参考执行代码时消耗的全网算力来制定Qtum gas价格方案。

在Qtum创建一个合约注资或者执行一笔交易,需要明确定义两个参数,即GasLimit和GasPrice。GasLimit定义了执行此合约可花费的gas总量;GasPrice定义了以Qtum聪为计价单位的gas价格。这样,在Qtum上执行合约的总花费则可以通过GasLimit乘以GasPrice获得。如果总花费超过了该合约支付的费用,则被视作无效交易。合约资金中减去执行合约的总花费,剩余的部分称之为交易规模费用(Transaction Size Fee)。这和标准的比特币交易费用模型十分类似。为了确定两个交易的优先级,矿工需要关注两个变量:一个变量是交易规模费用占总交易费用的比例(通常以最小代币值/KB计算)另一个变量是执行合约的GasPrice。这样,基于权益证明机制,矿工可以任意选择执行重要性和回报高的交易。这样的费用模型使Qtum交易执行更像是现实中的交易市场,矿工和用户可以按照各自的需求选择不同交易确认时间和交易费用。

(a) Qtum gas费用退还

在UTXO模型中,矿工收取的交易执行费用是无法灵活调整的。也就是说,当矿工发现执行交易比预期简单时,无法将部分费用退还给用户。因此,必须找到一种方式,能够退还部分费用,并且在出现out-of-gas的异常情况时,将交易回滚,并支付矿工相应的gas费用。

Qtum中利用在矿工的coinbase交易中添加新的交易输出来实现gas费用的退还。与此同时,Qtum还加入了新的区块验证共识机制,用于保证这些退款交易记录在coinbase中。否则,矿工可以选择保留这部分费用。

交易发起方的refund脚本可以作为输入以供输出脚本参考。通过简单地复制输出脚本,即可完成费用退还。目前,出于安全考虑,只有标准的pay-to-pubkeyhash或pay-to-scripthash可以用于执行退款。后续开发团队会评估该做法的安全性,考虑将此限制解除。

作为参考,OP_EXEC_ASSIGN的标准格式为:

输入:(按照入栈顺序)

· 花费交易哈希值(可选项)

· 版本号(使用虚拟机的版本号,目前仅有版本1)

· Gas Limit (执行合约可花费的gas总量)

· Gas Price (以Qtum聪为计价单位的gas价格)

· 数据(用于合约执行的数据)

· 智能合约地址

输出:(按照出战顺序)

· 可花费性(资金是否可以花费)

所以,EXEC_ASSIGN脚本为:

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

如果虚拟机执行结果出现了out of gas的异常情况,则可以使用OP_TXHASH进行资金的赎回,而该输出可供区块上的下一个交易使用。需要说明的是,这个输出是由运行vin[0].prevout 得到的通用地址交易脚本。在Qtum的早期版本中,只有通用地址交易(pubkeyhash Script)的发送人可以在虚拟机上进行资金往来。尽管Qtum虚拟机也可以执行其他形式的交易类型,但是msg.sender会在EVM中将被赋值为0,而且任何out-of-gas和gas费用退还的的资金将会保留在当前合约中。

(b) 未消耗gas退还模型

从另一个角度来看,Qtum的设计必须解决另外一个问题,即如何将未消耗的gas退还给合约。这样,用户可以放心的在合约中储存大量的资金以满足合约的正常运行需求,而没有使用的部分可以退还。

在区块上,使用vin[0].prevous执行交易的发起,并返回退还资金的地址信息。资金的退还机制在比特币交易费用模型基础上做了稍许调整:

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

需要说明的是,开发团队也曾考虑,使用“Credit_price”参数来衡量tx_relay_fee和gas_price,以方便矿工确认交易的优先级。

当合约执行完毕时,gas token的消耗就会从总资金中扣除(通过gas_limit和gas_price的乘积),剩余部分将会执行gas return script退还当前合约,并在coinbase交易中添加vin[0].prevout的通用地址交易输出信息(以便矿工获取他们的区块奖励)。只有通用地址交易的输出才可以得到gas的退还,否则退还的gas仍由矿工持有(在out-of-gas情况下,发送的资金仍将保留在合约中)。

目前在Qtum中仅支持单个EVM合约执行交易,所以不会出现两个合约执行同一个交易,并共享交易费用的情况。后续的开发过程中如果能够解决一些关键问题,我们可能会加入多个EVM执行同一个交易的功能。

(c) Gas refund特殊情况

矿工一定要对合约gas/资金的退还脚本多加留意。如果gas refund脚本的输出使区块大小超过最大值,则该合约交易无法被写入区块中,合约交易则由下一个区块重新执行。因此在执行合约前,矿工应该在候选区块(candidate block)中为refund脚本留下充足的空间。不遵循这条规则会导致合约多次执行refund脚本后才可发现无法在当前区块上执行该脚本。

如果没有gas费用退还,则没有相对应的费用退还输出。

在交易费用中包含gas_fee是需要达成共识的。如果区块上添加的交易会导致gas refund出现负值,或者gas_fee小于交易费用,则该交易及所在区块视为无效。

如果在操作脚本中有多个OP_EXEC或OP_EXEC_ASSIGN操作符,则该交易输出视为无效。虽然这种设计方案限制了脚本的能力,但更容易解决递归和EVM多方执行的问题。这样,可以通过静态分析来判断脚本的有效性,而不是通过执行脚本来判断。

【推荐】Qtum是如何让以太坊虚拟机运行在比特币模型上

图5:Gas Refund模型

Pubkeyhash TX: 通用地址交易;

Generation TX:产量交易;

Script Hash TX:合成地址交易;

Bitcoin transaction fee 比特币交易费用模型

+1
0


发表评论
相关文章
亚洲各地银行与加密货币行业情况小结
亚洲各地银行与加密货币行业情况小结
相约明年共此时——第二届全球普惠区块链峰会圆满落幕!
相约明年共此时——第二届全球普惠区块链峰..
能源巨头BP称已经测试了“内部”代币
能源巨头BP称已经测试了“内部”代币
如何使用比特币享受俄罗斯世界杯
如何使用比特币享受俄罗斯世界杯
IBM和Salon Media的区块链试点项目防止广告业诈骗
IBM和Salon Media的区块链试..
华为推出基于超级账本的区块链服务平台
华为推出基于超级账本的区块链服务平台

热文

合作伙伴


万向区块链实验室 趣块链社区 万向新链加速器 布比 币看 云币 Stellar 矩阵金融 网录科技 Bitse sosobtc China Ledger