Qtum研究院:如何在Qtum-x86虚拟机上创建智能合约?下篇

2023-10-30 19:30

本文主要是介绍Qtum研究院:如何在Qtum-x86虚拟机上创建智能合约?下篇,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

5月19日,Qtum联合创始人、核心开发工程师Jordan Earls发布了《Some Qtum-x86 Tech Details》,该文详细描述Qtum-x86相关技术细节,帮助开发者更加深入了解Qtum-x86虚拟机的运作过程,以及它的实际执行过程。

 

本篇文章将会分为上下两篇,第一篇用于介绍Qtum-x86合约如何上链及其Qtum-x86组成部分。第二篇讲述如何将DeltaDB设计为共识层上的底层数据存储。此篇为下篇,上篇可戳:Qtum研究院:如何在Qtum-x86虚拟机上创建智能合约?上篇

 

Qtum-x86消除状态限制

目前,EVM中的状态有很大的限制。它通过键-值对的形式存储,其中每个键和值的大小固定为256位。这种限制可能会加大开发人员管理不同的状态命名空间的难度。因此,Solidity通过自动操作每个存储变量所在的256位键空间中的位置来处理这个问题。这是基于变量名的哈希和/或在源文件中的位置生成的(取决于确切的Solidity版本等,这可以更改)。

 

通过以太坊节点/钱包将其存储在数据库中的实际方法是通过使用 “state trie”,也就是一颗Patricia树。尽管使用了可验证的加密树,在指定“根哈希”的情况下,节点始终能够证明一段状态的存在性且具有预期的值。但这不能在标准的Merkle树中实现,因为区块链中所有合约的整个状态都会被存储,并且重新计算一个包含数十万个不同状态元素的简单Merkle树,计算量太大,即使验证过程比根哈希的生成更快。

 

在Qtum-x86的设计中,最大的目标之一就是消除EVM中的状态限制。因此,可以在Qtum-x86使用动态长度的键和值,这就意味着需要一种全新的设计。

 

因此在Qtum-x86中,我们引入了DeltaDB设计。它是一个基于差异进行操作的新型数据库,不需要将区块链的整个状态编码改为单个可访问的数据结构。对于状态的键-值的大小没有直接的限制,但过大的大小可能会导致更新操作所需的gas成本会过于高昂,因此将很少更新的大数据与频繁更新的小数据划分开来,这样的状态分离操作是有益的。

 

目前Qtum-x86中的所有状态管理都是手动进行的,没有类似于Solidity对键名称的自动状态管理。未来可能会实现这种功能,但只适用于比C语言更高级的语言。不管怎样,使用传统的键-值数据库中的典型方法来管理键空间是很简单的。例如,如果一个名为“balances”的键-值对映射结构按地址索引并存储一个简单的64位整数,那么它可以像这样存储:

"balances_QddCMpVUf4gKTLseP5XFuVco6xy1YajbK7" -> 1000

 

当然,“balances_”是一个整数前缀,且地址将存储为原始字节(更好的是使用通用地址字节码格式),从而节省空间。因此,与具有256位长键和值的EVM相比,同等情况下x86的命名空间和键更易于手动管理。这种状态存储在节点/钱包数据库中的实现方式非常地简单直接。

 

例如:

"state_XZkyE7XAweUtrizgtry1RoMSv1p4zk9Rw8_balances_QddCMpVUf4gKTLseP5XFuVco6xy1YajbK7" -> 1000

 

其中“XZkyE7XAweUtrizgtry1RoMSv1p4zk9Rw8”为合约地址。当然,这些都是以字节编码的形式存储的,而不是浪费空间的字符串形式,这么写只是为了方便说明。这种方式使数据库的缓存与预测力会比在EVM中的同等情况下更加有效。因为读取由“随机”哈希索引的数据的不可预测性,EVM中有一个众所周知的问题就是要求全节点使用SSD。Qtum-x86节点会保留一些历史数据的副本以保持共识,但也需要对这部分数据进行修剪,因此,如果节点操作人只对当前状态感兴趣,而对历史状态不感兴趣的话,就可以安全删除500个区块之后的大部分历史数据。历史状态对于审计和某些特定的轻钱包应用程序而言特别有用,但对大多数用户来说并不是必需的。

 

实际在链上验证这种状态数据的方法也比以太坊EVM所使用的方法简单。在比特币的传统轻钱包“SPV”技术中,一个Merkle树的根节点哈希会存储在区块中,这可以用来证明交易确实包含在一个特定的区块中。然而,对于智能合约状态来说,我们不仅要证明简单的合约交易的存在性,也要证明当前的状态,以及交易收据和日志。

 

为此,Qtum-x86采用了一个“交错”的Merkle树,其中嵌套了每个账户的Merkle树。大多数Merkle树编码单一类型的数据列表。使用交错的方法,Merkle树代替编码成对数据,第一个数据是合约地址,第二个数据是账户“delta tree”。用于根Merkle树的交错方法可以更轻松地定位感兴趣的账户。也就是说,如果一个轻节点始终对某个合约状态感兴趣的话,那编码账户被修改的证明就会很简单。

 

当前区块中未修改过的账户将不会出现在根树中。更重要的是,这允许某种形式的抗审计力,其中可以反转概念以构建一个账户没有被修改过的证据。这可以通过获取所有已修改账户的列表及其各自的delta树来实现。很容易发现不是所有的数据都被接收(因为Merkle树哈希与区块数据不匹配),或者发现其中的一些数据被修改。

 

Delta树本身会编码一个“delta”列表。一个delta表示对合约账户的一次更改。这可以包括简单的(不定期)合约执行、合约发起的事件、状态更改或余额更改等。以太坊的“交易收据”概念也被编码成一个delta,这样就很容易证明合约已经执行,以及合约在执行过程中是否出现错误。

 

就技术而言,DeltaDB的概念比以太坊的state trie概念简单,但却能带来很多好处:

 

  1. 易于实现和审计(例如Qtum)

  2. 允许动态长度的键和值

  3. 非常易于扩展,允许将来在共识-关键树中对附加的数据进行编码,而不会破坏客户端和程序支持(需要执行硬分叉)

  4. 由于非随机索引键,更容易扩展和处理磁盘负载

  5. 允许任何账户的SPV节点进行审查检测

  6. 允许(缓慢的)检索任意和所有合约的所有历史合约状态,而不会重放交易,并提供数据丢失的证据

 

当然,它也有缺点:

 

  1. 未经验证的新设计

  2. 作为SPV节点获取所感兴趣的合约的所有状态可能需要与全节点进行更多的数据传输,因为不受信任的设置通常不能排除所有历史数据。但是,根据具体的合约设置,应该可以安全地排除一些历史数据。在使用抗审查性时,往返请求的数量也明显更高,因此预计这不会被用作“正常”的通信模式

  3. 由于需要空间、中间和临时(500个区块)历史数据,预计与以太坊上的同等设置相比,节点上的磁盘使用量将会增加,否则计算一次以上成本会非常高

 

智能合约升级

 

智能合约升级一直是合约生态系统中的一个痛点,EVM在这个方面没有任何优势。EVM不允许直接在已建立的合约账户中更改代码。社区所使用的解决方法是使用代理合约的概念。这种方法使用了一个特殊的“代理”合约,它可以响应某些请求(例如执行升级的请求),但是对于其他功能,它会委托给实际支持的合约,该合约可以通过升级功能来指向另一个新的合约。代理合约还包含支持智能合约的所有相关状态。这样就可以升级合约代码而无需重新部署或修改合约所使用的数据。

 

当然,EVM智能合约通常是以Solidity语言编写的。这进一步加大了升级过程的复杂度。正如上面的状态数据库所讨论的,Solidity会自动地操作所有状态变量和数组基于EVM存储的单个256位命名空间中的位置。在旧版本的Solidity中,这会引起简单的重构,例如旧状态变量上放置一个新的状态变量会破坏代码结构,从而导致Solidity尝试为旧状态变量读取/写入的不同位置,当然会带来灾难性的结果,也有许多的解决办法。但总的来说,就是由重构/升级的难度,额外的Gas成本,以及初始实施的难度所构成的权衡三角形。因此也有句流传至今的话叫做:“pick two that you want to be optimal”

 

Qtum-x86想要最大程度地消除这三角形带来的阻碍,并通过以下4种核心方式加以实现:

 

  • 简单的手动操作和明确的状态管理可避免智能合约开发人员陷入汇编或其他负担中

  • 可以直接升级合约代码,消除了对代理合约的需求

  • 引入了新的智能合约联盟机制,允许访问状态的中央“登记处”,而不会带来过高的gas成本

  • 通过引入一个权限系统,可以使用不受信任或半受信任的合约来安全地执行外部代码委托(委托调用),以确定委托调用的合约可以代表调用合约执行哪些操作

 

要做的有很多,但首先是状态管理。我们在上面关于状态数据库的部分中提到了这一点,最重要是开发人员可以控制状态所处的位置。尽管256位空间足够可以存储任意数量的不同状态的映射/数组,但它带来了不必要的复杂性,特别是它需要对映射结构中用于索引的键进行哈希处理。要在Solidity中显式执行此操作,还需要将其放到汇编级别,通常要编写许多包装函数。

 

常规状态变量leu中使用的这些包装函数很难被Solidity编译器优化,并且开发人员需要完全靠自己去处理位置的唯一性、边界检查、字段打包、字段拆分等。在Qtum-x86中对状态的处理就像典型的键-值数据库的操作一样简单。

 

访问中唯一真正的区别是,没有允许合约对键执行“通配符”搜索的方法,例如“返回数据库中以X开头的所有键”。执行这种查询的成本非常高,很难防止会导致消耗过多gas攻击,因此可以在Qtum-x86的数据库使用这个概念。简单的键名称空间是使用前缀创建的,键可以在不需要哈希计算的情况下存储,并且不需要分解结构或手动打包字节以满足某个常量大小。

 

接下来就是允许合约代码的升级。出于可证明性的原因,某些智能合约可能会选择禁用这个功能,从安全角度看,以太坊这样的区块链也不能这样升级。但这消除对代理合约的需求,并允许更简单地实现升级机制。

 

在Qtum-x86中,可以直接从外部合约读取状态。不需要在类ERC20的合约中实现getTokenBalance()等状态访问器函数。相反,可以使用类似这样的函数:

externalState(erc20Address, "balance", addressOfInterest, &balance)

这允许任何外部合约从公共空间读取状态。由于涉及到权限,写入状态的操作会更复杂。但基本上,状态合约会通过使用可信库提供的权限功能,或通过使用显式的修饰符函数来控制谁有权限写入该状态,其中可能带有验证格式等,以及尝试修改的一方已获得授权。可信库系统将允许使用类似代理的系统进行模块化的合约设计。但不是将所有代码委托给单个“代码”合约,而是可以将特定功能委托给特定合约。

 

此外,引入的权限系统将确保即使在这些委托功能合约中发现了漏洞受到限制。这意味着,如果一个类ERC20的合约委托了像“getBalance”这样的简单功能,则不允许修改状态或者在合约外部发送QTUM。​

这篇关于Qtum研究院:如何在Qtum-x86虚拟机上创建智能合约?下篇的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/310083

相关文章

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

在cscode中通过maven创建java项目

在cscode中创建java项目 可以通过博客完成maven的导入 建立maven项目 使用快捷键 Ctrl + Shift + P 建立一个 Maven 项目 1 Ctrl + Shift + P 打开输入框2 输入 "> java create"3 选择 maven4 选择 No Archetype5 输入 域名6 输入项目名称7 建立一个文件目录存放项目,文件名一般为项目名8 确定

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

Java 创建图形用户界面(GUI)入门指南(Swing库 JFrame 类)概述

概述 基本概念 Java Swing 的架构 Java Swing 是一个为 Java 设计的 GUI 工具包,是 JAVA 基础类的一部分,基于 Java AWT 构建,提供了一系列轻量级、可定制的图形用户界面(GUI)组件。 与 AWT 相比,Swing 提供了许多比 AWT 更好的屏幕显示元素,更加灵活和可定制,具有更好的跨平台性能。 组件和容器 Java Swing 提供了许多

智能交通(二)——Spinger特刊推荐

特刊征稿 01  期刊名称: Autonomous Intelligent Systems  特刊名称: Understanding the Policy Shift  with the Digital Twins in Smart  Transportation and Mobility 截止时间: 开放提交:2024年1月20日 提交截止日

基于 YOLOv5 的积水检测系统:打造高效智能的智慧城市应用

在城市发展中,积水问题日益严重,特别是在大雨过后,积水往往会影响交通甚至威胁人们的安全。通过现代计算机视觉技术,我们能够智能化地检测和识别积水区域,减少潜在危险。本文将介绍如何使用 YOLOv5 和 PyQt5 搭建一个积水检测系统,结合深度学习和直观的图形界面,为用户提供高效的解决方案。 源码地址: PyQt5+YoloV5 实现积水检测系统 预览: 项目背景

顺序表之创建,判满,插入,输出

文章目录 🍊自我介绍🍊创建一个空的顺序表,为结构体在堆区分配空间🍊插入数据🍊输出数据🍊判断顺序表是否满了,满了返回值1,否则返回0🍊main函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞+关注+评论+收藏(一键四连)哦~ 🍊自我介绍   Hello,大家好,我是小珑也要变强(也是小珑),我是易编程·终身成长社群的一名“创始团队·嘉宾”

Maven创建项目中的groupId, artifactId, 和 version的意思

文章目录 groupIdartifactIdversionname groupId 定义:groupId 是 Maven 项目坐标的第一个部分,它通常表示项目的组织或公司的域名反转写法。例如,如果你为公司 example.com 开发软件,groupId 可能是 com.example。作用:groupId 被用来组织和分组相关的 Maven artifacts,这样可以避免