跳到主要内容

简介

Move 是一种安全、沙盒化和经过形式验证的高级编程语言。它的首要用途是为 Diem 区块链提供基础实现。Move 允许开发者编写能够灵活管理和转移资产的程序,同时提供对这些资产遭受攻击的安全性和保护。同时,Move 也考虑了在区块链环境之外的应用场景。

Move 借鉴了 Rust 的做法,通过使用具有 move(Rust 中的关键字) 语义的资源类型来明确表示数字资产。

安装

$ cargo install --git https://github.com/move-language/move move-cli --branch main

上面的命令将在 Cargo 二进制目录中安装 move 二进制文件。在 Unix 上,这个目录通常是 ~/.cargo/bin。在终端测试安装是否成功

$ move -V
move-cli 0.1.0

模块和脚本

Move 中有两种类型的代码

  • 模块
  • 脚本

模块

模块遵循下面的结构

module <address>::<identifier> {
(<use> | <friend> | <type> | <function> | <constant>)*
}

模块使用关键字 module 声明, 紧跟着的 <address> 可以是一个确定性的地址或者定义在 Move.toml 中的地址。如在文件 Move.toml 中声明了下面的地址:

[addresses]
hello = "0x2"

则模块代码可以使用 hello 来指代地址 0x2

module hello::sbt {}

在模块中可以定义 struct 类型以及操作这些类型的函数。struct 类型定义了 Move 存储结构,而函数则定义了更新存储结构的方式。

脚本

脚本遵循下面的结构

script {
<use>*
<constants>*
fun <identifier><[type parameters: constraint]*>([identifier: type]*) <function_body>
}

使用 use 声明脚本中使用的模块。接着可以定义常量和方法。脚本中只能定义一个方法,方法名任意。需要注意的是, 脚本中不能定义变量, 结构体等,其目的仅是调用模块中的函数。

命令

包命令

  • move new <package_name> 创建项目
  • move build 编译 move 包
  • move build -p <path> 编译指定目录下的 move 包
  • move build --build-dir <path_to_save_to> 通过 --build-dir 指定编译后的文件目录
  • move prove 验证 move 包中的规范
  • move prove -p <path> 验证指定目录下 move 包中的规范
  • move test 运行 move 中的单元测试
  • move test -p <path> 运行指定目录下 move 中的单元测试

沙盒命令

沙盒允许在没有验证节点、区块链或交易的情况下编写和运行 Move 代码。持久数据以模拟 Move 内存模型的目录结构存储在磁盘上。

创建项目

$ move new hello

编译并运行脚本

在项目根目录下的 sources 目录创建一个名为 debug_script.move 的文件并输入以下内容:

// sources/debug_script.move
script {
use std::debug;
fun debug_script(account: signer) {
debug::print(&account)
}
}

在运行之前,需要先导入 Move 标准库,以便访问内置的 std 模块。可以在项目根目录下的 Move.toml 文件中指定为本地目录或使用远程路径。

[addresses]
std = "0x1" # Specify and assign 0x1 to the named address "std"

[dependencies]
MoveNursery = { git = "https://github.com/move-language/move.git", subdir = "language/move-stdlib/nursery", rev = "main" }
# ^ ^ ^ ^
# Git dependency Git clone URL Subdir under git repo (optional) Git revision to use

在沙盒中运行

$ move sandbox run sources/debug_script.move --signers 0xf
[debug] signer(0xf)

传递参数

也支持通过 --args 传递参数给 move sandbox run, 支持以下参数类型

  • bool
  • u64
  • address
  • 十六进制字符串
  • ASCII 字符串, 如 b"hi"

发布新模块

move sandbox run 命令将编译和发布该包中每个模块。例如有 Test 模块如下所示

// sources/Test.move
module 0x2::Test {
use std::signer;

struct Resource has key { i: u64 } // 资源对象

public fun publish(account: &signer) {
move_to(account, Resource { i: 10 }) // 创建资源, 并转移给 account
}

public fun write(account: &signer, i: u64) acquires Resource {
borrow_global_mut<Resource>(signer::address_of(account)).i = i;
}
}

执行编译

$ move build

在沙盒中部署模块

$ move sandbox publish -v

在项目的 storage 目录, 可以看到 Test 模块的字节码

$ ls storage/0x00000000000000000000000000000002/modules
Test.mv

通过 move view 命令查看编译的字节码

$ move sandbox view storage/0x00000000000000000000000000000002/modules/Test.mv
// Move bytecode v6
module 2.Test {
use 00000000000000000000000000000001::signer;


struct Resource has key {
i: u64
}

public publish(Arg0: &signer) {
B0:
0: MoveLoc[0](Arg0: &signer)
1: LdU64(10)
2: Pack[0](Resource)
3: MoveTo[0](Resource)
4: Ret
}
public write(Arg0: &signer, Arg1: u64) {
B0:
0: MoveLoc[1](Arg1: u64)
1: MoveLoc[0](Arg0: &signer)
2: Call signer::address_of(&signer): address
3: MutBorrowGlobal[0](Resource)
4: MutBorrowField[0](Resource.i: u64)
5: WriteRef
6: Ret
}
}

更新状态

通过脚本来调用发布的 Test 模块‘

// sources/test_script.move
script {
use 0x2::Test; // 引入 Test 模块
fun test_script(account: signer) {
Test::publish(&account)
}
}

该脚本调用了 Test 模块的 publish 方法,该函数将在签名者账户下发布一个类型为 Test::Resource 的资源。通过传递 --dry-run 可以模拟执行而不改变模块的状态。-v 表示显示资源的状态变更

$ move sandbox run sources/test_script.move --signers 0xf -v --dry-run
Changed resource(s) under 1 address(es):
Changed 1 resource(s) under address 0000000000000000000000000000000f:
Added type 0x2::Test::Resource: [10, 0, 0, 0, 0, 0, 0, 0] (wrote 40 bytes)
key 0x2::Test::Resource {
i: 10
}
Wrote 40 bytes of resource ID's and data
Discarding changes; re-run without --dry-run if you would like to keep them.

去掉 --dry-run 来实际运行

$ move sandbox run sources/test_script.move --signers 0xf -v
Changed resource(s) under 1 address(es):
Changed 1 resource(s) under address 0000000000000000000000000000000f:
Added type 0x2::Test::Resource: [10, 0, 0, 0, 0, 0, 0, 0] (wrote 40 bytes)
key 0x2::Test::Resource {
i: 10
}
Wrote 40 bytes of resource ID's and data

publish 方法会创建一个资源, 并转移给传入的地址。通过下面的命令查看发布的资源

$ move sandbox view storage/0x0000000000000000000000000000000f/resources/0x00000000000000000000000000000002::Test::Resource.bcs
key 0x2::Test::Resource {
i: 10
}

该命令的意思是查看 0xf 地址下拥有的 Test::Resource 资源数据

move sandbox clean 可清除 stroage 目录

参考资料