从 EVM 迁移到 Move,第一部分
相比之下,Move 采用了一种资源导向型方法,它源于 Solidity 的经验教训。
在 Move 中,代码存在于模块中(类似于合约,只是没有存储功能),数据作为资源存储在帐户中或作为独立对象存在,而不是在合约实例中。这是思维方式上的根本转变。Aptos 和 Sui 是两个著名的基于 Move 的区块链,它们都以自己的方式实现了这种范式。
Aptos Move:遵循最初的 Diem (Libra) 设计。区块链状态按帐户地址索引,每个地址可以保存任何给定资源类型的零个或一个实例。你可以把一个账户想象成一个存储其拥有的资源的储物柜。例如,Aptos Move 不会让 ERC-20 合约维护余额映射,而是为每个用户的账户发布该 Token 类型的 Balance 资源。转移 Token 意味着从 Alice 的 Balance 资源中移除价值,并将其存入 Bob 的账户,而不是更新中央合约账本中的条目。这种设计消除了对按地址显式映射的需求,因为地址是全局存储中的 key。
Sui Move:使用相同的核心 Move 语言,但具有以对象为中心的存储模型。Sui 中的每一条数据都是一个具有唯一 ID (UID) 的对象,并且交易必须指定它们读取或写入哪些对象。执行期间没有隐式的全局地址查找——如果合约(模块)需要更新某些内容,则必须传入该对象或将其声明为共享(全局)对象。即使是用户余额也是单独的 Coin 对象,而不是单个记录中的条目。例如,Alice 的 10 个 token 可以用一个总计为 10 的对象(或多个对象)表示,而向 Bob 发送 5 个 token 涉及拆分 Alice 的对象并将一个新的 5-token 对象转移给 Bob。Sui 的账户本质上是对象的所有者,而不是任意状态的容器。
EVM 是一个基于堆栈的虚拟机,具有全局共享状态(每个合约的存储按地址映射)。智能合约通过引用其他合约地址并通过 ABI 或底层调用调用函数来进行交互。
这种灵活性带来了复杂性:开发人员管理 msg.sender,通过地址调用其他合约,甚至使用诸如 delegatecall 和 call 之类的底层操作,这会引入安全隐患。
相比之下,Move VM 强制执行更多结构。Move 中的跨合约(跨模块)调用在编译时或通过显式模块导入来解析,而不是通过任意运行时地址调用。
Move 模块可以调用另一个模块的公共函数,但前提是该模块被声明为依赖项(使用 use 语句),或者其地址和名称是提前已知的。Move 中没有与 Solidity 的 delegatecall 等效的功能 - 模块无法模拟另一个模块的存储或在另一个模块的上下文中执行,从而消除了整类代理重入漏洞。此外,Move 没有在接收资产时触发的回退函数(fallback function )的概念;每个调用都是显式的函数调用,这简化了对控制流的推理。
在 Ethereum 中,区分了外部拥有的账户 (EOA) 与合约账户,但两者都只是地址 - 合约可以持有余额和代码。
在 Move 中,地址通常不直接持有代码。相反,模块被发布到地址(在 Aptos 中)或作为对象(在 Sui 中),然后作为可以调用的字节码模块存在。
Aptos 账户可以发布模块(如果它有权限),实际上使该地址成为代码的“所有者”,以便进行升级,但模块的逻辑是重点,而不是地址。在 Sui 中,模块存在于包中(包本身就是具有 ID 的对象)。因此,多个不同的合约(模块)可以存在于 Aptos/SUI 中的一个单一地址上
从 EVM 过渡过来的审计师需要调整他们的思维模式。在 Solidity 中,人们会检查合约如何相互调用、修改共享映射或委托执行。在 Move 中,你将了解模块如何管理资源:它们是否正确地将资源发布给正确的拥有者?他们是否在阻止未经授权的访问这些资源?
简而言之,第 1 部分的要点是 Move 用资源类型的状态和能力控制的入口函数取代了 Solidity 灵活的存储/调用模型。它在构建上更安全,但你需要围绕模块、能力和资源不变性重新设计审查 - 而不是代理和重入优先。
- 原文链接: x.com/VulsightSec/status...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!