Hello Move | Move dApp极速入门(一)
作者:李大狗、王宁波、陈俊锋 @ NonceGeekDAO
我们从二进制到汇编到各种高级语言,一直都在发展。智能合约也一样,从比特币的Script到以太坊的Solidity,往前跨了一大步,但是,Solidity能包打天下了吗?事实上,层出不穷的安全问题一直在困扰我们,在很大程度上限制了整个行业的发展,比如前段时间炒的沸沸扬扬的Poly Network被攻击事件。「安全」在金融场景,尤其是DeFi时代,比以往任何时候都更加重要,这些问题我们不能视而不见。如果区块链行业继续发展,势必会有更好的智能合约语言出来。
在这些大前提下,新的智能合约语言Move被设计出来了。Move是面向「资源」编程的。我个人认为,「面向资源编程」是智能合约语言的一个变革,说白了,智能合约语言又往前迈了一大步。
——jolestar
—— http://starcoin.org/zh/developer/blog/starcoin_move_resource
—— http://mirror.xyz/jolestar.eth/sQ0nMCO3eNig6gCzqQO7xew1mn8oUi1-rKtfZKmGlNI
本系列将以 Starcoin 为例,讲解 Move 语言以及 Move dApp 的开发,及其背后的计算机原理。
本系列的全文更新中,见:
http://github.com/WeLightProject/Web3-dApp-Camp/tree/main/move-dapp
同步的打卡任务:
http://github.com/WeLightProject/Web3-dApp-Camp/discussions/categories/projects-others
1 节点启动
下载最新的发行版 Starcoin 节点程序(MacOS 将其拷贝至 /usr/local/bin
目录即可):
http://github.com/starcoinorg/starcoin/releases
在此以 Starcoin
网络为基础,展现如何启动一个节点:
http://starcoinorg.github.io/starcoin-cookbook/docs/getting-started/setup/
太长不看版——关键命令合集:
# 启动一个本地 dev 节点 $ starcoin -n dev # 启动一个本地 dev 节点的同时打开控制台,-d 参数可以确保每次打开控制台时都保有历史的数据而不是重开 $ mkdir [folder_name] $ cd [folder_name] $ pwd $ starcoin -d [path_to_your_data_folder] -n dev console
starcoin 控制台命令:
# 指定账户获得测试代币 starcoin% dev get-coin 0xb7c46353c6c0e3a2559d5b12cad981e4 -v 100STC # 账户列表 starcoin% account list # 单一账户情况查看 starcoin% account show 0xb7c46353c6c0e3a2559d5b12cad981e4 # 创建新账户 starcoin% account create -p [pwd]
2 第一个 Move 合约 —— MyCounter
最小可实践例子:
http://github.com/starcoinorg/starcoin-cookbook/blob/main/examples/my-counter
module MyCounterAddr::MyCounter { use StarcoinFramework::Signer; struct Counter has key, store { value:u64, } public fun init(account: &signer){ move_to(account, Counter{value:0}); } public fun incr(account: &signer) acquires Counter { let counter = borrow_global_mut<Counter>(Signer::address_of(account)); counter.value = counter.value + 1; } public(script) fun init_counter(account: signer){ Self::init(&account) } public(script) fun incr_counter(account: signer) acquires Counter { Self::incr(&account) } }
MyCounter 源码分析
module 是发布在特定地址下的打包在一起的一组函数和结构体。使用script时需要与已发布的module或标准库一起运行,而标准库本身就是在 0x1 地址下发布的一组module。
module MyCounterAddr::MyCounter{ } 则在该MyCounterAddr地址下(对应Move.toml下的MyCounterAddr = "0xb7c46353c6c0e3a2559d5b12cad981e4")创建一个module。
use StarcoinFramework::Signer,是使用标准库下的Signer module,Signer 是一种原生的类似 Resource 的不可复制的类型,它包含了交易发送者的地址。引入signer类型的原因之一是要明确显示哪些函数需要发送者权限,哪些不需要。因此,函数不能欺骗用户未经授权访问其 Resource。具体可参考 源码 。
struct Counter has key, store { value:u64, }
使用struct定义了一个叫做Counter的结构体,同时被 key,store两种限制符修饰,Move的类型系统灵活,每种类型都可以被四种限制符所修饰。这四种限制符我们称之为 abilities,它们定义了类型的值是否可以被复制、丢弃和存储。 这四种 abilities 限制符分别是: Copy, Drop, Store 和 Key.
它们的功能分别是:
- Copy - 被修饰的值可以被复制。
- Drop - 被修饰的值在作用域结束时可以被丢弃。
- Key - 被修饰的值可以作为键值对全局状态进行访问。
- Store - 被修饰的值可以被存储到全局状态。
这里用key,store修饰,则表示它不能被复制,也不能被丢弃或重新使用,但是它却可以被安全地存储和转移。
下面则是定义的方法,
public fun init(account: &signer){ move_to(account, Counter{value:0}); } public fun incr(account: &signer) acquires Counter { let counter = borrow_global_mut<Counter>(Signer::address_of(account)); counter.value = counter.value + 1; }
定义格式则是:
public fun 函数名(参数:参数类型){ }
move函数默认是私有函数,只能在定义它们的模块中访问。关键字 public 将更改函数的默认可见性并使其公开,即可以从外部访问。
init方法参数是一个&signer,意味着该方法必须是一个账户合法签名过后才可以调用,move_to则是move的一个原语,作用是发布、添加Counter资源到 signer 的地址下。Move的账户模型,code和data是存储在一个账户地址下的。
下面是列举的常用原语
- move_to< T >(&signer, T):发布、添加类型为 T 的资源到 signer 的地址下。
- move_from< T >(addr: address): T - 从地址下删除类型为 T 的资源并返回这个资源。
- borrow_global< T >(addr: address): &T - 返回地址下类型为 T 的资源的不可变引用。
- borrow_global_mut< T >(addr: address): &mut T - 返回地址下类型为 T 的资源的可变引用。
- exists< T >(address): bool:判断地址下是否有类型为 T 的资源。。
incr方法参数也是一个&signer,意味着该方法必须是一个账户合法签名过后才可以调用,
关键字 acquires,放在函数返回值之后,用来显式定义此函数获取的所有 Resource。
Signer::address_of(account) 从签名者中拿到address
borrow_global_mut上面有介绍到,可变借用到address下到resource Counter,然后将Counter结构体下的value进行+1操作。
这下面的两个方法则是script方法,它与上面两个函数有什么区别呢?
- public fun : 方法可以在任何模块中被调用。
- public(script) fun:script function 是模块中的入口方法,表示该方法可以通过控制台发起一个交易来调用,就像本地执行脚本一样
下个版本的 Move 会用 public entry fun 替代 public(script) fun
Self则是代表自身module。
public(script) fun init_counter(account: signer){ Self::init(&account) } public(script) fun incr_counter(account: signer) acquires Counter { Self::incr(&account) }
2.1 编译
下载第一个实例的源码:
$ git clone [email protected]:WeLightProject/Web3-dApp-Camp.git $ cd Web3-dApp-Camp/move-dapp/my-counter
Move的包管理工具为Move Package Manager(mpm),它类似于Rust的Cargo或者Node的NPM。 可以通过 mpm package new my-counter
来创建一个新项目,典型的目录结构为:
my-counter ├── Move.toml └── sources └── MyCounter.move
- sources用来存档Move的模块,它类似于与Java中的类文件。
- Move.toml-用来存放配置文件:包括包的原数据、依赖和命名地址。
- 上述文件构成一个Move包(Move Package) 更详细的Move包管理参考 文档
修改 move.toml
中的地址为你用来部署的地址。
编译:
$ mpm release
接下来会在 release
文件夹中,看到你编译好的二进制文件。
2.2 控制台部署
在 Starcoin Console 中执行如下命令即可部署:
starcoin% dev deploy [path to blob] -s [addr] -b
-s 即--sender,-b即--blocking,表示阻塞等待命令执行完成
如果遇到账户被锁,用 unlock
命令解锁即可。
account unlock [addr] -p [pwd]
其中 pwd
即是在 1.2
中创建的密码。
部署成功后能看到:
:bulb:需要注意的是,在Move中代码存储在个人的地址上,而非像以太坊那样的公共地址上。因此合约部署后并不会创建新地址,当我们想要调用合约时需要采用部署合约人的地址+合约名来调用该合约。
2.3 控制台调用
http://starcoinorg.github.io/starcoin-cookbook/docs/move/interacting-with-the-contract
- 调用 init_counter 脚本函数来初始化资源。
starcoin% account execute-function --function {MyCounterAddr-in-Move.toml}::MyCounter::init_counter -s 0x23dc2c167fcd16e28917765848e189ce -b
其中:
{MyCounterAddr-in-Move.toml}::MyCounter::init_counter
- 查看Counter资源
starcoin% state get resource 0x23dc2c167fcd16e28917765848e189ce 0x23dc2c167fcd16e28917765848e189ce::MyCounter::Counter
在Move中合约的数据被称为 资源(resource)
,由于读取数据不改变链上状态,因此不需要-s -b,不会执行交易,也不消耗状态。
感兴趣的同学可以试着调用 incr_counter
,并再次查看 Counter
是否+1。
- 如何在智能合约中调用另一个合约的函数
- gas gasPrice
- NFTScan 与 ET.XYZ 在 NFT API 数据层面进行深度合作
- Move Prover 实用指南
- 一种转移并在Os拍卖不可转移灵魂绑定代币的方法
- vscode智能合约的插件——SCLens及个人介绍
- 操作资源 | Move dApp 极速入门(三)
- 第一个 Move dApp | Move dApp 极速入门(二)
- 项目介绍:世界杯竞猜
- Ethernaut 题库闯关 #18 — Magic Number
- 抓完X2Y2十万NFT订单,分析版税可以不收后多少用户真这么做了?
- Web3系列教程之进阶篇---4. 去中心化的代码协作协议 Radicle
- 一文讲清-DeFI王者AAVE最新的稳定币GHO提案
- Hello Move | Move dApp极速入门(一)
- 明星公链Aptos初体验--发送交易和构建合约
- NFT租赁提案EIP-5006步入最后审核!让海外大型游戏的链改成为可能
- “模块化”区块链简介
- 一个DeFi纵价攻击事件背后的数学原理分析
- 【解读合约审计】Harmony的跨链桥是如何被盗一亿美金的?
- NFT流动性市场安全问题频发—NFT交易平台Quixotic被黑事件分析