501-move基础数据类型
0x-wen

move入门与交互

新建项目

1
sui move new my_project

编译项目

Move 是一种编译语言,需要将源文件编译为 Move Bytecode,它仅包含有关模块、其成员和类型的必要信息,不包括注释和一些标识符(例如常量)。

Move Compiler 会创建一个文件夹,其中放置所有获取和编译的依赖项以及当前包模块的字节码。
生成的文件应该被添加到.gitignore

1
sui move build 

运行测试

1
2
sui move test
sui move test test_hello # 指定运行某个或多个测试

部署脚本

todo-list 复制链接中的代码,并按操作部署到测试网

1
sui client publish --json

合约交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# 找到合约部署后packageId
"type": "published",
"packageId": "0x102f24e8218fa6fb837137ada5a0ba30bac96e30b085bd6de99a11727b794a79",

# 准备变量
export PACKAGE_ID=0x102f24e8218fa6fb837137ada5a0ba30bac96e30b085bd6de99a11727b794a79
export MY_ADDRESS=$(sui client active-address)

# 调用合约
sui client ptb \
--gas-budget 100000000 \
--assign sender @$MY_ADDRESS \
--move-call $PACKAGE_ID::todo_list::new \
# 将new函数的返回值存储至 list 中
--assign list \
# 将 list 对象传输给 sender
--transfer-objects "[list]" sender

# 执行成功后得到交互的响应信息,ObjectID类似一个TodoList的实例,拥有其所有权并可以调用其相关方法
Created Objects:
ObjectID: 0x3ac554c410b36c309313eced79e6d86e251637b80ab54180c4d44b86c0538064
Sender: 0x7074c1cfb8327dcefcf6f44d14d1747bd24859df02a8ba2f31eaf6504385cf79
Owner: Account Address ( 0x7074c1cfb8327dcefcf6f44d14d1747bd24859df02a8ba2f31eaf6504385cf79 )
ObjectType: 0x102f24e8218fa6fb837137ada5a0ba30bac96e30b085bd6de99a11727b794a79::todo_list::TodoList

# 配置LIST_ID
export LIST_ID=0x3ac554c410b36c309313eced79e6d86e251637b80ab54180c4d44b86c0538064

# 添加一个任务
sui client ptb \
--gas-budget 100000000 \
--move-call $PACKAGE_ID::todo_list::add @$LIST_ID "'0'"

# 查看
sui client object $LIST_ID

# 添加三个并删除两个, 验证同一个事务按下标删除
sui client ptb \
--gas-budget 100000000 \
--move-call $PACKAGE_ID::todo_list::add @$LIST_ID "'1'" \
--move-call $PACKAGE_ID::todo_list::add @$LIST_ID "'2'" \
--move-call $PACKAGE_ID::todo_list::add @$LIST_ID "'3'" \
--move-call $PACKAGE_ID::todo_list::remove @$LIST_ID 0 \
--move-call $PACKAGE_ID::todo_list::remove @$LIST_ID 0

# 删除多个的场景下会有错误,目前还没有找到啥原因
# 复现步骤:
# 1.单独添加0 2.单独添加1 3.合并 删除0和1
sui client ptb \
--gas-budget 100000000 \
--move-call $PACKAGE_ID::todo_list::remove @$LIST_ID 0 \
--move-call $PACKAGE_ID::todo_list::remove @$LIST_ID 1 \
--move-call $PACKAGE_ID::todo_list::remove @$LIST_ID 2 \
--move-call $PACKAGE_ID::todo_list::remove @$LIST_ID 3

# Error executing transaction: Failure
error: "MoveAbort(MoveLocation { module: ModuleId { address: 0000000000000000000000000000000000000000000000000000000000000001, name: Identifier(\"vector\") }, function: 14, instruction: 11, function_name: Some(\"remove\") }, 131072) in command 1"

相关概念

包由模块组成,包发布到区块链上并由地址标识。

  • 调用其函数的事务来与已发包的包交互
  • 可以作为其他包的依赖,例如:自己编写的包可以依赖官方包

已发布的包

  • 开发过程中包没有地址,一般需要设置为 0x0
  • 已发布的包会有一个链上唯一地址,其中包含其模块的字节码,已发布的包不可变,并且可以通过发送交易与其交互

模块

  • 模块包含函数、类型、常量、变量等
  • 模块可以引入其他依赖包, 以todolist为例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
module   todo_list    ::   todo_list
定义模块 包/address :: 模块名称

# 引入其他依赖包, std包/string模块/String类型
use std::string::String;

# 定义结构体
public struct TodoList has key, store {
id: UID,
items: vector<String>
}

# 定义函数
public fun new(ctx: &mut TxContext): TodoList

Move.toml

  1. [package]: 包信息
    • name: 导入时的包名称
    • version: 包的版本号
    • edition: Move的版本
  2. [dependencies]: 依赖包
    • override = true, 解决版本冲突问题
    • git 指定github仓库地址, local = path 指定本地路径
    • subdir = “remote/path”
    • rev = “main” 指定分支
  3. [addresses]: 地址
    • 部分用于添加地址的别名,可以在此指定任意地址,然后在代码中用作别名

Address

地址是区块链上位置的唯一标识符。它用于识别包、帐户和对象, 地址的固定大小为32字节,通常使用16进制表示

长度为 64 个字符(32 个字节),并以 0x 为前缀

1
2
3
4
>>> len("0x04bde040cca2b5fec3c47a30cdeb3e11f011395c49886c91629b7dbd4713b319")
66
>>> len("04bde040cca2b5fec3c47a30cdeb3e11f011395c49886c91629b7dbd4713b319")
64

标准库的地址是 0x1 。小于 32 字节的地址在左侧用零填充。

1
2
3
4
5
6
0x1 = 0x0000000000000000000000000000000000000000000000000000000000000001   # Sui 标准库的地址(别名 std )
0x2 - Sui 框架的地址(别名 sui )
0x5 - Sui System 对象的地址
0x6 - 系统 Clock 对象的地址
0x8 - 系统 Random 对象的地址
0x403 - DenyList 系统对象的地址

Account

  • 账户是识别用户的一种方式,账户由私钥生成并由地址标识。
  • 账户可以拥有对象,并且可以发送交易,每笔交易都有一个发送者(地址)
  • Sui支持多种密码算法生成账户,ed25519, secp256k1, zklogin

Transaction

与链交互的唯一方式,发起交易用于改变区块链的状态。

  1. 交易结构

    • sender: 交互的操作者是谁
    • list (or a chain) of commands: 要执行的操作
    • command inputs: 简单类型值也可以是object
    • gas object: 用于支付gas费用对象
    • gas price and budget: 预估交易成本
  2. commands

    • 交易由多个命令组成,并按照它们列出的顺序执行。并且可以使用之前命令的结果
    • 交易整体作为一个事务,要么全部成功,要么失败
      1
      2
      3
      4
      5
      6
      7
      Inputs:
      - sender = 0xa11ce

      Commands:
      - payment = SplitCoins(Gas, [ 1000 ])
      - item = MoveCall(0xAAA::market::purchase, [ payment ])
      - TransferObjects(item, sender)
    1. SplitCoins - 一个内置命令,用于从传递的对象(在本例中为 Gas 对象)中分离出新硬币
    2. MoveCall - 使用给定参数调用包 0xAAA 、模块 market 中的函数 purchase 的命令 - 给定参数 payment object
    3. TransferObjects - 将对象传输给接收者的内置命令
  3. 交易结果

交易对区块链状态的改变,可以通过以下方式更改状态:

  • 使用 gas object 来支付交易
  • 创建、更新和删除对象
  • 记录事件

交易结果的组成:

  • Transaction Digest: 交易摘要 - 交易的哈希值,用于识别交易
  • Transaction Data: 交易数据 - 交易中使用的输入、命令和气体对象
  • Transaction Effects: 交易效果 - 交易的状态和“效果”,更具体地说:交易的状态、对象及其新版本的更新、使用的气体对象、交易的气体成本以及交易发出的事件
  • Events: 事件 - 交易发出的自定义事件
  • Object Changes: 对象更改 - 对对象所做的更改,包括所有权的更改
  • Balance Changes: 余额变化 - 交易涉及的账户总余额的变化
由 Hexo 驱动 & 主题 Keep
总字数 41.7k