What is Move ? Learn the Move programming language with Libra Blockchain
Move is a new programming language developed to provide a secure and programmable foundation for the Libra Blockchain. An account in the Libra Blockchain is where an arbitrary number of Move resources and Move modules are stored. Every transaction sent to the Libra Blockchain uses a transaction script written in Move to encode its logic. Transaction scripts can call procedures declared by a module to update the global state of the blockchain.
In the first part of this tutorial, I’ll give a high-level introduction to the main features of the Move language:
- Move Transaction Scripts Allows Programming LibraCoin Transactions
- Move Modules Enables Incorporation of “Smart Contracts”
- Move First-Class Resources
For the curious, the Move technical article contains more details about this programming language. Custom Moves are not supported in the initial testnet release, but these features are available for you to try in your test environment.
Main features of Move
Move Transaction Scripts allow transaction programming
- Each Libra transaction includes a Move transaction script that encodes logic that the validator will execute on behalf of the client (for example, to transfer Libra from A’s account to B’s account).
- Transaction scripts interact with Move Resources published in the Libra Blockchain’s global storage by calling the procedures of one or more Move modules.
- A transaction script is not stored in the global state and it cannot be called by other transaction scripts. This is a single use program.
- I will show some examples of trading scripts in the examples section below
Write a trading script
As I explained above (Move Transaction Scripts), the user writes a transaction script to request an update to the Libra Blockchain’s global storage. There are two important building blocks that will appear in almost any trading script: type LibraAccount.T
and LibraCoin.T
Resources. LibraAccount
is the name of the module and T
is the name of the Resource declared by that module. This is a common naming convention in Move; The main type of the area declared by a module is usually named T.
When a user “has an account at address 0xff
on Libra Blockchain”, what I mean is this address 0xff
contains an instance of LibraAccount.T
Resource. Each non-empty address has a LibraAccount.T
Resource. This resource stores account data, such as sequence numbers, authentication keys, and balances. Any part of the Libra system that wants to interact with the account must do so by reading data from LibraAccount.T
Resource or call procedures of LibraAccount
module.
Account balance is a kind of resource LibraCoin.T
. As I explained in Move Resources, this is a Libra coin. This type is a “first-class citizen” in the language just like any other Move Resources. LibraCoin.T
Resources can be stored in program variables, passed between procedures, etc.
I encourage you to be interested in the Move IR definitions of these two main resources in LibraAccount
and LibraCoin
modules in directory libra/language/stdlib/modules/
Now let’s see how a programmer can interact with these modules and resources in a Transaction Scripts.
import 0x0.LibraAccount;
import 0x0.LibraCoin;
main(payee: address, amount: u64)
let coin: R#LibraCoin.T;
coin = LibraAccount.withdraw_from_sender(move(amount));
LibraAccount.deposit(move(payee), move(coin));
return;
This Transaction Scipt has the unfortunate problem that it will fail if there is no account under the address payee
. I will fix this problem by modifying the script to create an account for payee
if the account does not exist.
import 0x0.LibraAccount;
import 0x0.LibraCoin;
main(payee: address, amount: u64)
let coin: R#LibraCoin.T;
let account_exists: bool;
coin = LibraAccount.withdraw_from_sender(move(amount));
account_exists = LibraAccount.exists(copy(payee));
if (!move(account_exists))
create_account(copy(payee));
LibraAccount.deposit(move(payee), move(coin));
return;
Let’s look at a more complex example. In this example, I will use the Transaction script to pay multiple recipients instead of just one.
import 0x0.LibraAccount;
import 0x0.LibraCoin;
main(payee1: address, amount1: u64, payee2: address, amount2: u64)
let coin1: R#LibraCoin.T;
let coin2: R#LibraCoin.T;
let total: u64;
total = move(amount1) + copy(amount2);
coin1 = LibraAccount.withdraw_from_sender(move(total));
coin2 = LibraCoin.withdraw(&mut coin1, move(amount2));
// Perform the payments
LibraAccount.deposit(move(payee1), move(coin1));
LibraAccount.deposit(move(payee2), move(coin2));
return;
To better understand the Transaction Scripts supported by Libra Blockchain in the first testnet version, you can refer to this directory in Libra Core. libra/language/stdlib/transaction_scripts
.
Writing Modules
Now I will write my own Move module instead of just reusing my existing modules LibraAccount
and LibraCoin
modules.
Let’s give the following example: User #1 will create an account at address a at some point in the future. User #2 wants to “spend” some money on User #1 so he can pull them into his account once it is created. But User #2 also wants to be able to get his/her money back if User #1 never creates an account.
To solve this problem for User #2, I will write a module EarmarkedLibraCoin
:
- Declare a new resource type
EarmarkedLibraCoin.T
wrap Libra coin and recipient address. - Allow User #2 to create such a type and publish it in his account (
create
procedure). - Allow User #1 to request resources (
claim_for_recipient
procedure). - Allow anyone to have
EarmarkedLibraCoin.T
can destroy it (unwrap
procedure).
module EarmarkedLibraCoin
import 0x0.LibraCoin;
resource T
coin: R#LibraCoin.T,
recipient: address
public create(coin: R#LibraCoin.T, recipient: address)
let t: R#Self.T;
t = T
coin: move(coin),
recipient: move(recipient),
;
move_to_sender(move
return;
public claim_for_recipient(earmarked_coin_address: address): R#Self.T
let t: R#Self.T;
let t_ref: &R#Self.T;
let sender: address;
t = move_from(move(earmarked_coin_address));
t_ref = &t;
sender = get_txn_sender();
assert(*(&move(t_ref).recipient) == move(sender), 99);
return move
public claim_for_creator(): R#Self.T
let t: R#Self.T;
let coin: R#LibraCoin.T;
let recipient: address;
let sender: address;
sender = get_txn_sender();
t = move_from(move(sender));
return move
public unwrap(t: R#Self.T): R#LibraCoin.T
let coin: R#LibraCoin.T;
let recipient: address;
T coin, recipient = move
return move(coin);
User #2 can generate some Libra Coin for User #1 by creating a Transaction Script called create
on the address of User #1 and LibraCoin.T
owned by User #2. When a created, User #1 can request funds by sending a transaction from a . This calls claim_for_recipient
, pass the result to unwrap
and return storage LibraCoin
wherever he wants. If User #1 takes too long to create an account under a and User #2 wants to claim his money back, User #2 can do so using claim_for_creator
follow unwrap
.
You may have noticed that the code in this module is agnostic to the internal structure of LibraCoin.T
. It can easily be written in generic programming (for example, resource T coin: AnyResource, ...
).
The article ends here. Hopefully through this article, it will help you better understand Libra Coin as well as the Move programming language.
Good luck.
Bitcoin Magazine | Sirquy
Follow the Twitter page | Subscribe to Telegram channel | Follow the Facebook page
Bình luận