在当今的区块链技术领域,MoveVM作为一种关键的技术组件,在Sui中发挥着重要作用。本文将深入剖析MoveVM的各项技术细节,包括其初始化过程、代码缓存机制、发布模块与脚本的流程,以及函数执行和二进制格式等核心内容。一、MoveVM初始化MoveVM的初始化相对简洁高效,仅需
在当今的区块链技术领域,Move VM作为一种关键的技术组件,在 Sui中 发挥着重要作用。
本文将深入剖析Move VM的各项技术细节,包括其初始化过程、代码缓存机制、发布模块与脚本的流程,以及函数执行和二进制格式等核心内容。
Move VM的初始化相对简洁高效,仅需初始化一个Loader
实例,其内部实质是少量由Mutex
保护的空表,如HashMap
和Vec
的实例。这一初始化过程成本较低,为后续操作奠定了基础。
而Loader
在整个VM生命周期中扮演着代码缓存的关键角色,代码并非提前全部加载,而是在运行时,当函数和脚本执行之际按需加载。
一旦加载完成,模块和脚本便以加载后的形式被复用,随时可迅速投入执行,极大提高了执行效率。
Vec<u8>
形式呈现),此过程可能触发网络访问。Loader
进行缓存。此后,在该VM实例的生命周期内,对已加载模块的引用无需再次执行上述复杂的获取、验证及转换操作。在常见的客户端场景中,系统交易执行硬升级时可能会打破代码缓存的一致性。
此时,适配器需暂停处理交易,直至客户端重启。不同的客户端可能采用各异的“代码模型”,如版本控制机制等。
因而,持有Move VM实例的客户端必须深谙代码缓存的行为特性,提供与已加载代码兼容的数据视图(DataStore
)。
并且,当特定条件致使代码缓存一致性改变时,客户端有责任释放当前VM实例并重新实例化新的VM。
客户端若要在系统中发布模块,需调用publish_module
函数,该函数接收模块的二进制数据(已序列化)、发送者地址以及GasMeter
引用作为参数,VM在接收到发布请求后会执行一系列严谨的步骤:
StatusCode
的错误信息。StatusCode::MODULE_ADDRESS_DOES_NOT_MATCH_SENDER
错误。StatusCode::DUPLICATE_MODULE_NAME
错误。StatusCode
的错误。脚本在Move VM中扮演着执行特定逻辑事务的角色,它本质上是在script
块中声明的Move函数,通过调用链上发布的框架来达成任务。VM执行脚本时遵循以下步骤:
sha3_256
哈希值,此哈希值将作为脚本的唯一标识,用于访问脚本缓存。StatusCode
的错误。senders
向量中的账户地址创建的Signer
值。args
向量中的其他参数,对照预设的许可类型白名单进行筛选,只有匹配白名单的参数才会被添加到脚本的参数列表中。若发现任何不匹配的类型,VM将返回StatusCode::TYPE_MISMATCH
错误。自Move VM 2.0版本起引入的脚本函数,与常规脚本有诸多相似之处,其字节码源自具有script
可见性的链上模块中的Move函数。
执行脚本函数时,VM首先依据模块和函数名从链上模块加载相应函数,并着重检查其是否具备script
可见性。
在完成加载与可见性检查后,其余的执行步骤与普通脚本执行流程如出一辙,即构建参数列表、调用解释器执行等。
若在执行过程中发现指定函数不存在,VM将返回FUNCTION_RESOLUTION_FAILURE
状态码;若函数不具备script
可见性,则会触发EXECUTE_SCRIPT_FUNCTION_CALLED_ON_NON_SCRIPT_VISIBLE
状态码。
Move VM提供了强大的功能,允许通过ModuleId
和函数名执行模块中的任意函数。鉴于函数名在模块内具有唯一性(不存在重载情况),执行时无需提供函数签名。整个执行过程由VM分三步完成:
Module
,若加载过程出现错误,执行将立即中断,并返回带有合适StatusCode
的错误信息。StatusCode::TYPE_MISMATCH
错误。二进制头部(Binary Header):作为二进制数据的开篇,包含三个关键部分。Magic
固定为4字节的0xA1, 0x1C, 0xEB, 0x0B
,可视为一种标识;Version
是4字节的小端无符号整数,用于指示版本信息;Table count
则以ULEB128形式记录表的数量,当前最大表数量通常限制在1字节内。
表头部(Table Headers):紧跟二进制头部之后,其数量与“Table count
”定义相符。每个表头部都有特定格式,包括1字节的Table Kind
用于标识表的类型,ULEB128格式的Table Offset
指明表内容起始位置相对于表头部末尾的偏移量,以及ULEB128格式的Table Length
记录表内容的字节数。各表在存储时必须紧密相连,不得存在间隙,内容也严禁重叠。
各表详情(Tables):涵盖多种类型的表,如MODULE_HANDLES
用于标识模块位置,通过一对索引指向ADDRESS_IDENTIFIERS
表中的账户地址和IDENTIFIERS
表中的模块名;STRUCT_HANDLES
能唯一确定用户类型,包含模块、名称、是否为资源以及类型参数等信息;FUNCTION_HANDLES
用于精准定位函数,涵盖函数所在模块、名称、参数与返回类型索引以及类型参数等关键要素。其他表如FUNCTION_INSTANTIATIONS
、SIGNATURES
、CONSTANT_POOL
等也各自承担着描述函数实例化、签名、常量池等重要职责,每个表的格式都经过精心设计,以满足VM运行时的各种需求。
辅助定义(Kinds、SignatureTokens、Bytecodes等):
Type Parameter Kind
定义了1字节的类型参数种类,如ALL
表示可被资源或可复制类型替代,COPYABLE
限定只能被可复制类型替代,RESOURCE
则要求必须被资源类型替代。SignatureToken
作为1字节的标识,用于表示不同的数据类型,像BOOL
、U8
、U64
等基本类型,以及STRUCT
、TYPE_PARAMETER
、VECTOR
等复杂类型,通过特定的组合规则能够准确描述函数的参数与返回值类型。Bytecodes
构成了Move VM的指令集,每条指令由1字节的操作码(opcode)和可能存在的负载(payload)组成,不同的操作码对应诸如POP
、RET
、BR_TRUE
等不同的操作,负载则依据操作码的具体需求而定,用于实现VM的各种运算、跳转、数据操作等功能。模块与脚本特定数据(Module Specific Data、Script Specific Data):
ModuleHandle
表,用于明确自身模块在众多模块中的位置。FUNCTION_DEFINITIONS
表,其入口点相关信息在二进制末尾依次描述,包括若脚本入口点为泛型时的类型参数信息(如数量与种类)、参数类型索引以及函数体字节码(含长度与具体字节码序列)。综上所述,Move VM通过精心设计的初始化、代码缓存、执行流程以及二进制格式等多方面机制,为区块链应用提供了高效、稳定且可靠的运行环境,助力区块链技术的蓬勃发展。
深入理解这些技术细节,对于开发人员优化基于Move VM的应用、解决潜在问题具有至关重要的意义。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!