30

深入Libra: 使用Move编程语言编写Libra模块和脚本 | 鸟窝

 4 years ago
source link: https://colobu.com/2019/10/15/dive-into-Libra-write-modules-and-scripts-in-Move-language/?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

深入Libra: 使用Move编程语言编写Libra模块和脚本

这一次,我们将尝试编写简单的Libra模块和脚本,初步了解Move编程语言。

Move编程语言还在演化之中,白皮书参照Move: A Language With Programmable
Resources
, 现阶段只能通过Move Intermediate Representation (IR) 编写,要求请不要太高。Libra能活下来Move才能光大。

本文主要整理和参考官方文档: Run Move Programs Locally

birdcoin.png

注意,当前自定义的模块和脚本只能运行在Libra本地网络中,测试网络上是不支持的。

  • 模块(Module): 模块定义了更新Libra区块链的全局状态的一些规则, 类似其它区块链中的智能合约。模块声明了发布在某个账号上的资源,每个账号就是包含一组资源和模块的容器。
    • 在模块中声明了struct类型(包括资源)和过程(procedure)
    • 过程定义了创建、访问、和销毁它声明的类型
    • 模块可以重用,可以调用其它模块的过程
    • 用户在它自己的账号下发布模块
  • 脚本:准确的说是交易脚本,允许对交易进行编程。
    • 每个Libra交易中都包含一个交易脚本,比如转账操作
    • 交易和发布在Libra区块链全局存储中的资源进行交互,这是通过调用一个或者多个模块的过程实现的
    • 脚本并不存储在全局状态中,脚本不能调用脚本,它只使用一次
  • Move语言中资源是第一类的:
    • Move的主要功能是定义自定义资源类型。资源类型用于编码具有丰富可编程性的安全数字资产
    • 资源是Move语言中的普通值(ordinary value),它们可存储为数据结构,作为参数传递给procedure,从procedure返回等等
    • Move类型系统为资源提供了特殊的安全保障。Move资源不能复制、重复使用或丢弃。资源类型只能由定义该类型的模块创建或销毁。这些保障是由Move虚拟机通过bytecode验证静态地强制执行的。Move虚拟机将拒绝运行尚未通过bytecode检验器的代码
    • Libra币作为一种资源类型,其名称为LibraCoin.T。注意LibraCoin.T在语言中没有特殊的地位,每种资源都享有相同的保护

Libra本身的模块和脚本分别位于modulestransaction_scripts, 通过这些已有的模块和脚本,你可以学习Move相关的操作。

下面我们以一个代币 BirdCoin (鸟币) 为例,演示如何在本地网络进行:

  • 模块的编写、发布
  • 脚本的编写与执行
  • 相关过程的编写:查询余额、取钱、存钱、挖矿等操作

编译、发布模块

编写第一个模块

1、首先,我们定义一个代币,叫做BirdCoin, 换成人话就是鸟币。一般我们使用T代表这个模块的主要资源。
这个资源有一个u64类型的值,用来代表币值。

module BirdCoin {
resource T {
value: u64,
// ......

2、定义一个初始化用户币值的方法,只需调用一次。

public initialize() {
move_to_sender<T>(T{ value: 0 });
return;

3、接下来定义挖矿、查询余额、取款和存钱的过程。

public mint(value: u64): Self.T {
return T{value: move(value)};
public balance(): u64 acquires T{
let sender_account: &Self.T;
let token_value: u64;
sender_account = borrow_global<T>(get_txn_sender());
token_value = *(&move(sender_account).value);
return move(token_value);
public deposit(payee: address, to_deposit: Self.T) acquires T{
let payee_token_ref: &mut Self.T;
let payee_token_value: u64;
let to_deposit_value: u64;
payee_token_ref = borrow_global_mut<T>(move(payee));
payee_token_value = *(©(payee_token_ref).value);
T{ value: to_deposit_value } = move(to_deposit);
*(&mut move(payee_token_ref).value) = move(payee_token_value) +
move(to_deposit_value);
return;
public withdraw(amount: u64): Self.T acquires T{
let sender_account: &mut Self.T;
let value: u64;
sender_account = borrow_global_mut<T>(get_txn_sender());
value = *(©(sender_account).value);
assert(copy(value) >= copy(amount), 1);
*(&mut move(sender_account).value) = move(value) - copy(amount);
return T{ value: move(amount) };

1、模块必须和一个账号绑定,我们首先启动一个本地网络:

cargo run -p libra_swarm -- -s
libra%

2、然后创建一个账号:

libra% a c
>> Creating/retrieving next account from wallet
Created/retrieved account #0 address 4b6db7161fb394e287b1b9a45629740fe23b71566c8e976416f8d47bbe80438a

3、接着编译上面的模块

libra% dev c 0 /Users/xxxxx/libra_local_network/move/birdcoin.mvir module
>> Compiling program
Finished dev [unoptimized + debuginfo] target(s) in 0.43s
Running `target/debug/compiler -l /var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/786d6a4502e5910b3a0706fa68e91963.mvir -m`
Finished dev [unoptimized + debuginfo] target(s) in 0.40s
Running `target/debug/compiler /var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/786d6a4502e5910b3a0706fa68e91963.mvir -a 4b6db7161fb394e287b1b9a45629740fe23b71566c8e976416f8d47bbe80438a -m`
Successfully compiled a program at /var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/786d6a4502e5910b3a0706fa68e91963.mv

4、发布模块

上面的模块编译到/var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/786d6a4502e5910b3a0706fa68e91963.mv, 你将它发布在第0个账号下。

libra% dev publish 0 /var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/786d6a4502e5910b3a0706fa68e91963.mv
waiting ........transaction is stored!
no events emitted
Successfully published module

下面我们需要编写一个脚本,用来初始化账号的鸟币,以及尝试挖矿、存钱以及查询操作。

因为CLI没有直接的命令操作鸟币, 我们在脚本中使用assert进行验证。

编写交易脚本

下面是一个交易脚本,这里我们直接使用\{\{sender\}\}.BirdCoin导入模块,因为我们以下的测试都是以这个账号进行测试的。你也可以直接使用这个账号导入模块,因为发布的模块是公共的,可以被其它模块或者脚本使用。

import \{\{sender\}\}.BirdCoin;
main() {
let sender: address;
let minted_tokens: BirdCoin.T;
let balance: u64;
sender = get_txn_sender();
BirdCoin.initialize();
minted_tokens = BirdCoin.mint(100);
BirdCoin.deposit(move(sender), move(minted_tokens));
balance = BirdCoin.balance();
assert(move(balance) == 100, 3);
return;

在这个脚本中,我们首先为这个账号初始化值为0的鸟币,然后挖出100个鸟币, 存入到这个账号上。

经过这一系列的操作,账号的账上应该有100个鸟币了。

libra% dev compile 0 /Users/xxxxx/libra_local_network/move/birdcoin_script.mvir script
>> Compiling program
Finished dev [unoptimized + debuginfo] target(s) in 0.73s
Running `target/debug/compiler -l /var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/f3e8e68584dc01dc2953ff887203324f.mvir`
Finished dev [unoptimized + debuginfo] target(s) in 0.40s
Running `target/debug/compiler /var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/f3e8e68584dc01dc2953ff887203324f.mvir -a 4b6db7161fb394e287b1b9a45629740fe23b71566c8e976416f8d47bbe80438a --deps=/var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/5070552218b6e5bbea6a2029931d4664`
Successfully compiled a program at /var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/f3e8e68584dc01dc2953ff887203324f.mv
libra%
libra% dev execute 0 /var/folders/gq/jd9v5dd95p570hkztblb8ht40000gn/T/f3e8e68584dc01dc2953ff887203324f.mv
waiting ........transaction is stored!
no events emitted
Successfully finished execution

Gitalking ...


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK