近期,随着Sui主网即将上线,围绕Aptos和Sui的讨论也逐渐增加,社区也非常活跃,大家都在讨论Aptos和Sui的异同。其实公链技术并没有绝对的优势和劣势,主要还是看与业务的适用程度以及基础性能、安全性等。SharkTeam之前对Aptos、Sui、StarCoin等Move语言公链进行
近期,随着Sui主网即将上线,围绕 Aptos 和 Sui的讨论也逐渐增加,社区也非常活跃,大家都在讨论Aptos和Sui的异同。其实公链技术并没有绝对的优势和劣势,主要还是看与业务的适用程度以及基础性能、安全性等。
SharkTeam之前对Aptos、Sui、StarCoin等Move语言公链进行了深入研究,我们将进行一些对比和分享,这是第一期,希望对Move开发者选择适合自己业务的公链有帮助。
Aptos 和 Sui 都是 PoS 共识模型,但是两者细节实现有些不同。
Aptos 采用基于 BFT 的 HotStuff,在此基础上,Aptos 开发了 Block-STM执行引擎。Block-STM 执行引擎提高了吞吐量降低了延迟。
Sui 采用了 Narwhal 和 Tusk。Narwhal 是基于 DAG 的内存池模块(mempool),主要负责交易数据的可用性。Tusk 是共识模块,主要是对负责交易进行排序。
在以太坊中有两个账户:EOA 和 合约账户。账户的本质是地址,在 Aptos 和 Sui 中,地址有所不同。
类型 | 大小 |
Aptos(Core Move) | 32字节 |
Sui | 20字节 |
在Aptos中,每个账户是由资源和模块组成,每个账户可以拥有多个资源和模块。资源是存储数据,模块是存储代码。
在Sui中,没有账户这一说法。Sui的最小单位是对象(Object),所有创建的对象都会在0x0地址上。该0x0地址,一般是创建的包。比如,我用sui move new learn创建的一个项目,在Move.toml中
Core Move 提供了四种能力: Copy、Drop、Store、Key。
在 struct 中,Copy和Drop可以用于创建类似Solidity中 event,来获取日志信息。拥有Store 和 Key,可以被认为资源对象。
Aptos 和 Core Move 能力特性一样。
Aptos 使用Core Move中的全局存储操作符(move_to,move_from等)。使用全局存储操作符必须具有相应的acquires关键字去注释全局资源。
Sui 有 Sui 对象,没有 Aptos 的acquires关键字。Sui 对象要存储在链上必须要有 Key 并且 struct 中要有一个特殊的成员字段id,它的类型是 sui::object::UID。对象 UID具有唯一性,它通过 object::new(\&mut TxContext) 创建,并通过 object::delete(UID) 销毁。
Sui 和 Aptos(Core Move)不同,拥有 Key 能力,并不意味着能够全局存储。
在Aptos(Core Move)中,任意 struct 被 Key 修饰后都可以作为资源储存在账户中。合约在执行的时候,无论是不是被访问账户,都可以通过borrow_global等一些全局资源操作符去访问。
在 Sui 中,对象是sui -> move中直接传递,不能借助全局操作符。比如,在 Sui 中存储对象必须通过函数transfer::transfer(object, address)进行存储。但是,该函数智能在entry函数中使用。因为 entry 函数是用来对象资源交易入口函数。
Aptos(Core Move) | Sui | |
Move module | public/public(friend)/public(script) | public/public(friend) |
Ability | Copy、Drop、Store、Key | Copy、Drop、Store、Key |
Resource(Object) | 组装和拆包只能在当前module执行 | 组装和拆包只能在当前module执行,默认Object是Owned(0x0) |
在Aptos(Core Move)中 Shared 的所有权主要通过创建资源账户,并且绑定资源账户,合约之间间接共享。
在 Sui 中的某些对象不能被任何人修改,这些对象可以被读取。比如 Sui 中所有已发布的包和模块都是不可变对象。
transfer::freeze_object(obj)
在 Sui 中还有一种共享对象可以被任何人读取或修改,并且该共享对象交易需要通过共识协议进行全局排序。
transfer::share_object(obj)
在Aptos中,一个交易的签名者(signer)被直接作为一个参数传递到从Move外部调用的函数中。
签名者(signer)是 Move 内置的资源类型。签名者(signer)是一种允许持有者代表特定地址(address)行使权力的能力(capability)。你可以将原生实现(native implementation)视为:
struct signer has drop { a: address }
std::signer 标准库模块为 signer 提供了两个实用函数:
函数 | 描述 |
signer::address_of(\&signer): address | 返回由 \&signer 包装的地址值。 |
signer::borrow_address(\&signer): \&address | 返回由 \&signer 包装的地址的引用。 |
signer 有点像 Unix UID,因为它表示一个通过 Move 之外的代码(例如,通过检查加密签名或密码)进行身份验证的用户。
在 Sui中,TxContext类型可以像对待 signer 一样被声明为一个函数的参数,并且可以使用一个库函数从TxContext中获得签名者(signer)。此外,TxContext 还用于在Sui Move中创建 UID 。
Aptos 在module部署时,采用signer传入init_module。
init_module(account: &signer)
Aptos 支持在具有类似签名的module部署时调用的初始化函数。 Sui 将在module部署时调用使用类似签名声明的 init函数。
init(&mut TxContext)
整数溢出问题,出现在Solidity 0.8之前版本中。Solidity 0.8之前采用的是SafeMath安全库去处理溢出问题,Solidity 0.8之后溢出问题在语言层面不在出现,Solidity自带溢出处理。如果发生溢出,将会revert。
那么,在Move中是否纯在溢出问题。我们简单写了一个测试例子。
从测试结果中可以得知,Move在语言层面处理了溢出问题。如果发生溢出,Move 会出现 arithmetic error。
在Solidity 0.8之后,位运算不精确使用也会发生数值问题。
Move 中的位运算也同样存在相同问题。
适当的使用位运算可以节省gas,但是同时要保证精确计算,否则会发生数值问题。
在Solidity中,对于基本的访问控制,Openzepplin提供了一个合约安全模板Ownable。在该合约中,账户的所有者可以被赋予特定的独占访问权限。
在Move中提供了一些ability(key/store),通过ability对资源对象进行授权操作。同时,Move中也有常用的设计模式,它允许以资源对象为中心来进行适当的访问控制。这种设计模式类似于有一个相应权限的"帽子"(Cap),我将一个struct赋予key能力但是不赋予store。如下所示:
struct AdminCap has key{}
在Aptos(Core Move)中,Cap的设计如下:
在Sui中,Cap的设计如下:
在AdminCap struct 中,Sui 和 Aptos 相比,Sui 多了UID类型的id。Sui是没有账户地址的概念,只能使用id进行索引对象。
在init函数中,我们创建了一个AdminCap的一个副本,将其发送到发布者的地址,让发布者拥有Cap。
在create_and_send函数中,传入AdminCap并且立即采用_未使用变量符号对它使用。由于是引用对象,所以原来对象未变化。这时候,只有AdminCap拥有者才能进行调用执行该函数。
SharkTeam的愿景是全面保护Web3世界的安全。团队由来自世界各地的经验丰富的安全专业人士和高级研究人员组成,精通区块链和智能合约的底层理论,提供包括智能合约审计、链上分析、应急响应等服务。已与区块链生态系统各个领域的关键参与者,如Polkadot、Moonbeam、polygon、OKC、Huobi Global、imToken、ChainIDE等建立长期合作关系。
Twitter:<https://twitter.com/sharkteamorg>
Discord:<https://discord.gg/jGH9xXCjDZ>
Telegram:<https://t.me/sharkteamorg>
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!