Aptos合约开发之HelloWorld详解篇

  • 欧皇.eth
  • 更新于 2022-09-13 15:47
  • 阅读 3659

以Hello World程序为例,来熟悉Aptos工程中的基本概念。

前言

在上篇文章里,我们一起搭建了Aptos开发环境,并且成功运行了Hello World程序。接下来,我将以Hello World程序为例。一起来熟悉Aptos工程中的基本概念。

关键词

Aptos工程项目拆解、Move语法、Cargo包管理工具、测试用例

Aptos工程项目拆解

image.png

接下来,我会使用上图中的Move.toml和HelloAptos.move文件来进行讲解。

Move.toml

Aptos项目的包管理工具使用的是Cargo。Cargo的作用和Python的pip,Nodejs的npm类似。

在Move.toml文件中,依赖包的来源有很多种,例如crates.io、git仓库、本地库文件等等。自然而然,不同的来源应当有不同的书写方式。

通常情况下,我们使用以下两种的方式来设置依赖包,基本上就能满足绝大多数的场景需求。

  • 依赖包来自于crates.io时候,需要列出包名称和版本。
  • 依赖包来自于git仓库时,需要指定git地址、相关分支名等。
[dependencies]
time = "0.1.12"
只需要名称和版本字符串。默认情况下,Cargo是准备在crates.io上查找依赖项。

rand = { git = "https://github.com/rust-lang-nursery/rand.git" }
由于我们尚未指定任何其他信息,因此 Cargo 假定我们打算使用最新的提交master分支来构建。

rand = { git = "https://github.com/rust-lang-nursery/rand", branch = "next" }
我们指定了next分支,那么Cargo就会拉取next分支的包。除此之外,你还可以将git字段和rev、tag还有branch这些用于指定其他内容的字段搭配起来使用。

AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework/", rev = "devnet" }
我们指定了subdir文件夹和devnet分支,然后Cargo将拉取git路径的subdir文件夹下的devnet分支来构建我们的程序。

至此,除了这两种常用的引包方式外,更多关于Cargo设置依赖的方法,这里就不再罗列赘述了,需要查看的请移步查看。

http://llever.com/cargo-book-zh/reference/manifest.zh.html#dependency-sections

HelloAptos.move

Move语法这里不做罗列赘述。只把我认为使用频率较高的先列出来,其余语法遇到再学不迟。

数据类型:

  • 基本数据类型:整型 (u8, u64, u128)、bool、address
  • 自定义数据类型:Struct
  • Resource 类型
  • 内置数据类型:Vector
  • 签名者数据类型:signer

基本的数据类型里没有浮点型,那么小数计算如何处理呢?

Solidity中通过单位的不同处理小数,10^18 wei=1 ether,并且Solidity有SafeMath这样的lib可供加减乘除使用。

那Aptos呢?在Aptos里,你可以把Solidity的Safemath用Move重写一遍,或者使用Sui已封装好的lib。这个在后续的文章中再进行研究。

传统资产合约编程,最大也是最多的安全问题就是:类型溢出。Move的一个大特色,就是用Resource类型来解决这一程序员编程遇到的bug问题。

Resource数据类型,是一种特殊的结构体类型。Resource只能用struct进行定义,同时必须使用key这个abilitities。换言之,只有key,store能力,没有drop,copy的就是resource。

对resource的增删改查需要通过特殊的函数进行包裹后进行调用,特殊的函数是指的borrow_global和borrow_global_mut。

Resource的定义

//Resouce是一种特殊的结构体类型。Resource只能用struct关键字定义,同时必须拥有key、store这两种abilitities。
//例如HelloAptos.move中的Message
struct Message has key{
    msg:string::String,
    message_change_events: event::EventHandle<MessageEvent>,
}

这里的Message就是合约的resource。简单点理解,resource就像一个保险箱,你只能用你自己的账号打开并且操作保险箱里面的内容。你能做的操作只是对属于你的资源(resource)进行增删改查。

Resource的增删改查

  • 添加元素
    
    //移动resource到account需要使用内置函数move_to()。第一个参数
    native fun move_to<T: key>(account: &signer, value: T);

move_to(account, Message { msg:message, message_change_events: event::new_event_handle<MessageEvent>(account), });

- 删除元素

move_to(account, Message { msg:message, message_change_events: event::new_event_handle<MessageEvent>(account), });

- 修改元素

//可变引用(&mut): 可变引用赋予我们读取和更改值的能力。 //native fun borrow_global_mut<T: key>(addr: address): &mut T; let old_message = borrow_global_mut<Message>(account_addr); //修改resource中的内容 old_message.msg = message;

- 查询元素

//全局函数 borrow_global 返回了对 Resource T 的不可变引用。不可变的引用(&)允许我们在不更改值的情况下读取值。其签名如下: //native fun borrow_global<T: key>(addr: address): &T;

*&borrow_global<Message>(addr).msg

//全局函数 borrow_global_mut 返回了对 Resource T 的可变引用可变引用(&mut)赋予我们读取和更改值的能力。 //native fun borrow_global_mut<T: key>(addr: address): &mut T;


- 检查资源

exists<Message>(account_addr)


### 自定义数据类型
- struct
struct的定义方式和C语言的的很类似。

### 打印日志
- debug::print()

debug::print(&account_addr);//打印账户地址 debug::print(&1234); //打印1234

需要注意的是,目前move的debug和assert功能都不完善,传参都是用引用。

## 测试用例

[test(account = @0x1)]

public entry fun sender_can_set_message(account: signer) acquires Message { let addr = signer::address_of(&account); say_message(&account, b"Hello, Aptos"); debug::print(&account); debug::print(&3456); //无法打印字符串,因为move没有string类型 //let log : string::String = b"hello world!"; //debug::print(&log); assert!( get_message(addr) == string::utf8(b"Hello, Aptos"), ENO_MESSAGE ); }

在HelloAptos.move中编写好测试用例后,控制台输入`sudo aptos move test`。在控制台可以看到debug的日志。

Running Move unit tests [debug] 0000000000000000000000000000000000000000000000000000000000000001 [debug] (&) { 0000000000000000000000000000000000000000000000000000000000000001 } [debug] 3456 [ PASS ] 0xfbd4140a63e8fe7d6e9e25aff78e11876b1b6c21bc8d34b51cbfff40ca03164b::Message::sender_can_set_message Test result: OK. Total tests: 1; passed: 1; failed: 0 { "Result": "Success" }



今天就先讲解到这儿,因为Resource是Move里很重要的数据类型,是它让Move变得独一无二,安全且强大。所以在接下来的文章里,咱们一起动手操作Resource,加深我们对Resource的认识。

### 参考文档

- https://github.com/MystenLabs/sui/blob/main/crates/sui-framework/deps/move-stdlib/sources/fixed_point32.move

- http://llever.com/cargo-book-zh/reference/manifest.zh.html#dependency-sections
点赞 2
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
欧皇.eth
欧皇.eth
一位懂区块链的项目经理。 微信公众号:一位懂技术的PM