Qtum x86 虚拟机技术文档连载(三)

112 阅读6分钟


UTXO 交互(UTXO Interaction)


Qtum-x86 合约可以直接与包含它们的交易的各个部分进行交互。这尤其适用于 “见证” (witness) 正常支付交易的合约。在这种情况下,合约会读取花费了 Token 的地址(或者多个地址),以便将这些 Token 发送至另一个地址。合约会记录这个操作过程或者做一些其他的处理,例如将 XRC20 Token 自动发放给发送方。在 EVM 合约中也可以实现这种功能,但实现过程会更加复杂,同时,向不同类型的地址发放 Token 需要特别小心,否则会导致异常交易的产生。

合约事件(Contract Events)

与 EVM 相比,版本迭代上最大的改进之一是 Qtum-x86 中实现的合约事件功能。事件(在以太坊中称为“日志”)指的是数据位,它们不会直接保存到区块链中,但可以证明其在区块链中的存在性。在以太坊中,日志的数据格式是非常严格的,由“主题”字段——4个32字节长的数据构成的字节数组,和“数据”字段——32字节长的数据构成。因此,对于那些值超过2^256的数据,通常使用256位来散列处理。

Qtum-x86 虚拟机没有数据大小限制,事件由键-值对字段构成,且每个字段都带有类型 ID。这使得合约可以使用预期的表现形式(即作为地址数字与字符串)来创建数据,使得用户无需其他特殊的工具或者编码知识就可以方便地理解数据。

合约升级(Contract Upgrades)

与 Solidity/EVM 合约相比,Qtum-x86 中的合约升级非常简单。实现这一功能最大的原因是,可以直接对合约的字节码进行修改。这可以消除对 Solidity 中众所周知的冗长的代理合约模式的依赖。我们不再需要将状态,地址和字节码切分成不同的合约,从而降低合约升级的成本。如果是很小版本的升级的话,可能只需要对单个区域的字节码进行修改即可。这有效地减少了交易大小的膨胀,从而降低了此类升级的 gas 消耗。之后我们会提供选项来禁用这种通过修改合约字节码进行升级的方式,用来保证合约的字节码100%的不可篡改。

另一个简化升级的原因是对状态的显示处理。在 EVM 中合约状态的键和值长度有着 256 字节长的限制。这要求 Solidity 编译器自动生成 Solidity 合约中实际使用的键数据。这是一 个需要不断改进的主题,但在大多数情况下,这使得你无法彻底重构合约中代码的布局方式,也无法对涉及重命名存储变量的代码进行重大重构。在 Qtum-x86 虚拟机中,存储是通过合约进行显式管理的,没有“可变的” (variable) 抽象的概念。不定长的键和值数据允许将复杂的结构存储为一个键或值,从而可以直接使用 Qtum-x86 的存储。这样我们就可以轻松地对重构和升级进行管理,而不会受到很大的限制。同时数据也可以更为方便地转化成到其他不同的格式。

EVM 中对数据的限制也使得在 Qtum-x86 中不会出现安全问题。在 EVM 中,基于数组结构存储的变量可以通过索引随机访问,这使得对 256 位存储空间之后的地址进行变量读写操作成为可能。而 Qtum 中不存在这个漏洞,因此允许动态存储数组索引是安全的。

通用地址系统 (Universal Address System)

Qtum 中有多种不同类型的地址。这与以太坊完全不同,以太坊中有两类账户,但共用同一个地址空间:外部账户,该类账户被公钥-私钥对控制;合约账户,该类账户被存储在账户中的代码控制。Qtum 中有以下几种地址类型:

  1. Pay to pubkey

  2. Pay to pubkeyhash

  3. Pay to scripthash

  4. Pay to witness pubkeyhash

  5. Pay to witness scripthash

  6. EVM 合约

  7. x86 合约

  8. 后续可能的VM地址或者私有链地址

以前在 Qtum 的 EVM 中,只能与 EVM 合约或者 pay to pubkeyhash 类型的地址进行交互。这是因为受限于 EVM 的设计,它只允许160位长的地址。在无损地址安全性的情况下,不可能对不超过160位长的地址和“类型”进行编码,并且 Qtum 中的某些地址类型并不能调整成160位长。

Qtum-x86 虚拟机中,我们引入了通用地址(UniversalAddress)的概念。这是一种对类型和数据同时进行编码而产生的地址,旨在保证地址在主网,测试网,回归测试网,甚至是 Qtum 区块链的分叉网络中格式的一致性。这与 Qtum 中使用 Base58 进行地址编码完全不同。 “类型”会加倍(doubles)以便用户读取地址前缀。


如果用户可以轻松地将主网 Token 发送到测试网地址,或者将主网地址误认为是测试网地址或者其他区块链的地址,可能会带来糟糕的后果。因此,应该使用不同的地址“前缀”以便用户区分不同的区块链类型。


另一方面,通用地址仅限于在智能合约中使用,而对终端用户来说几乎是不可见的。当前在 Qtum-x86 中,地址的数据部分是定长的,但在将来的设计中,它的长度可以是动态可变的。

除了能与这些地址类型进行实际交互之外,使用通用地址系统还能轻松过滤并且确定所使用的地址的类型,而无需其他任何区块链的信息。

外部合约状态访问(External Contract State Access)

在 Qtum-x86 虚拟机中,可以直接读取外部合约的状态信息,不必像在 Solidity/EVM 合约中那样,使用 "getter" 方法来获取。而每个合约都应该对外发布一个由各个密钥所构成的开放状态 “API” ,密钥格式需保证在合约中不会发生变化,甚至可以通过合约字节码升级来对密钥进行持久化处理。

共享合约通信堆栈(Shared Contract Communication Stack)


新型的内存区域-共享合约通信堆栈,可以在 Qtum-x86 智能合约中使用。这是一个简单的堆栈,可以被单个执行操作中的所有智能合约访问。这个堆栈可以用来在不同的合约间传递参数并且返回数据。堆栈允许单独管理多个数据块,这使得对可变数量的参数以及返回数据的处理变得非常简单。在此之后也将介绍一种基于此功能构建的ABI格式。


回顾:第二篇主要为“Hello World”合约的创建和调试,本篇文章主要介绍为x86虚拟机的新特性。