MOVE - programming language. General information

Hi all! If you love Aptos so much, then I think you should know more about the programming language MOVE.

So, let’s begin:

Let’s take a closer look at the main characteristics of the Move language and what are its key differences with another, already popular language for smart contracts - Solidity (on the Ethereum platform).

Move is an executable bytecode language that is used to execute user transactions and smart contracts. Pay attention to two points:

  1. While Move is a bytecode language that can be directly executed on the Move virtual machine, Solidity (the smart contract language on Ethereum) is a higher-level language that is first compiled into bytecode before being executed on the EVM (Ethereum Virtual Machine). ).

  2. Move can be used not only to implement smart contracts, but also for user transactions (more on this later), while Solidity is a language only for smart contracts

A key feature of Move is the ability to define custom resource types with semantics based on linear logic: a resource can never be copied or implicitly deleted, only moved. Functionally, this is similar to the features of the Rust language. Values in Rust can only be assigned to one name at a time. Assigning a value to another name makes it inaccessible under the previous name

Representation of digital assets in open systems

10 Likes

There are two properties of physical assets that are difficult to represent digitally

1. Rarity (Scarcity, in the original - scarcity). The number of assets (issue) in the system must be controlled. The duplication of existing assets must be prohibited, and the creation of new ones is a privileged operation.

2. Access control. The system participant must be able to protect assets with access control policies.

These two characteristics, which are natural for physical assets, must also be implemented for digital objects if we want to consider them assets. For example, a rare metal has a natural scarcity, and only you have access to it (holding it in your hands, for example) and you can sell or spend it.

To illustrate how we arrived at these two properties, let’s start with the following sentences:

Suggestion #1: The simplest rule without scarcity and access control

  • G[K]:=n means updating the number available by key K in the global state of the blockchain with the new value n.
  • transaction ⟨Alice, 100⟩ means setting Alice’s account balance to 100.
4 Likes

The above solution has several major problems:

  • Alice can receive an unlimited amount of coins by simply sending transaction ⟨Alice, 100⟩.
  • The coins Alice sends to Bob are worthless, since Bob could send himself an unlimited number of coins using the same technique.

Suggestion #2: Account for the deficit

2 Likes

Now we monitor the situation so that the number of Ka coins is at least equal to n before the transfer transaction. However, although this solves the scarcity problem, there is no information about who can send Alice’s coins (for now, anyone can do this, as long as you do not violate the quantity limit rule).

Suggestion #3: Combining scarcity and access control

We solve this problem by using the verify_sig digital signature mechanism before checking the balance, which means that Alice uses her private key to sign the transaction and confirm that she is the owner of her coins.

Blockchain programming languages

Existing blockchain languages ​​face the following problems (all of which were solved in Move (note: unfortunately, the author of the article only refers to Ethereum in his comparisons, so you should consider them only in this context. For example, most of the following are also solved in EOS )):

Indirect representation of assets. An asset is encoded using an integer, but an integer value is not the same as an asset. In fact, there is no type or value representing bitcoin / ether / ! This makes it difficult and error-prone to write programs that use assets. Patterns such as passing assets to/from procedures or storing assets in structures require special support from the language.

The deficit is not expandable. Language represents only one scarce asset. In addition, the defense against scarcity is hardwired directly into the semantics of the language itself. The developer, if he wants to create a custom asset, must carefully control all aspects of the resource himself. These are exactly the problems of Ethereum smart contracts.

Users issue their assets, ERC-20 standard tokens, using integer numbers to determine both the value and the total supply. Whenever new tokens are created, the smart contract code must independently check that the issuance rules are met. In addition, the indirect representation of assets leads, in some cases, to serious errors - duplication, double spending, or even complete loss of assets.

Lack of flexible access control. The only access control policy currently in place is a signature scheme using asymmetric cryptography. Like scarcity protection, access control policy is deeply embedded in the semantics of the language. But how to extend the language to allow programmers to define their own access control policies is often a very non-trivial task.

This is also true for Ethereum, where smart contracts do not have native support for cryptography for access control. Developers must manually write access control, for example, using the onlyOwner modifier.

Even though I am a big fan of Ethereum, I believe that asset properties should be natively supported by the language for security purposes. In particular, passing Ether into a smart contract enables dynamic dispatch, which has introduced a new class of bugs known as re-entrancy vulnerabilities. Dynamic dispatch here means that the code execution logic will be determined at run time (dynamic) and not at compile time (static).

Thus, in Solidity, when contract A calls a function of contract B, contract B can run code that was not intended by the developer of contract A, which can lead to reentry vulnerabilities (contract A accidentally executes the function of contract B to withdraw money before the actual deduction account balances).

Move Language Design Fundamentals

Resources of the first order

At a high level, the interaction between modules/resources/procedures in the Move language is very similar to the relationship between classes/objects and methods in OOP languages.

Modules in Move are similar to smart contracts in other blockchains. The module declares resource types and procedures that define rules for creating, destroying, and updating declared resources. But all this is just conventions (“jargon”) in Move. A little later we will illustrate this point.

Flexibility

Move adds flexibility to Libra through scripting. Every transaction in Libra includes a script, which is actually the main procedure of the transaction. The script can either perform one specified action, for example, making payments to a specified list of recipients, or reuse other resources, for example, by calling a procedure that defines common logic. This is why Move transaction scripts offer a lot of flexibility. A script can use both one-time and recurring behaviors, while Ethereum can only execute recurring scripts (calling a single smart contract method). The reason it is called “repeated” is because smart contract functions can be executed multiple times. (note: here the moment is very delicate. On the one hand, transaction scripts in the form of pseudo-bytecode are also in Bitcoin. On the other hand, as I understand it, Move expands this language, in fact, to the level of a full-fledged smart contract language).

Safety

The Move executable format is bytecode, which, on the one hand, is a higher-level language than assembler, but lower-level than source code. The bytecode is checked in run-time (on-chain) for resources, types, and memory safety using a bytecode verifier and then executed by the interpreter. This approach allows Move to provide the security of source code, but without the compilation process and the need to add a compiler to the system. Making Move a bytecode language is a really good idea. It does not need to be compiled from source, as in the case of Solidity, there is no need to worry about possible failures or attacks on the compiler infrastructure.

Verifiability

We are aiming to make the checks as light as possible as it is all on-chain off-chain static verification tools. Although this is more preferable, the development of verification tools (as a separate toolkit) has been postponed for the future, and only dynamic verification in run-time (on-chain) is currently supported.

Modularity

Move modules provide data abstraction and localize critical resource operations. The encapsulation provided by the module, combined with the protection provided by the Move type system, ensures that properties set on module types cannot be violated by code outside the module. This is a well-thought-out abstraction design, meaning that the data inside the contract can only be changed within the framework of the execution of the contract, but not from the outside.

3 Likes

2 Likes

Move Overview

The sample transaction script demonstrates that malicious or careless actions by a programmer outside of a module cannot compromise the security of the module’s resources. Next, we will look at examples of how modules, resources, and procedures are used to program the Libra blockchain.

Peer-to-peer payments

The number of coins given in amount will be transferred from the sender’s balance to the recipient.

There are several new points here (highlighted in red inscriptions):

0x0: account address where the module is stored

Currency : module name

Coin : resource type The coin value returned by the procedure is a resource value whose type is 0x0.Currency.Coin

move() : value cannot be used again

copy(): value can be used later

Let’s break down the code: in the first step, the sender calls a procedure named withdraw_from_sender from the module stored in 0x0.Currency. At the second stage, the sender transfers funds to the recipient by moving the value of the coin resource into the deposit procedure of the 0x0.Currency module.

Here are three examples of errors in code that will be rejected by checks:

Duplicating funds by changing the call to move(coin) to copy(coin) . Resources can only be moved. Attempting to duplicate the amount of a resource (for example, by calling copy(coin) in the example above) will result in an error during bytecode validation.

Reuse funds by specifying move(coin) twice. Adding the line 0x0.Currency.deposit(copy(some_other_payee), move(coin)) to the example above will allow the sender to “spend” the coins twice - once with the payee and once with some_other_payee. This is an undesirable behavior that is not possible with a physical asset. Fortunately, Move will reject this program.

Loss of funds due to refusal to move(coin) . If the resource is not moved (for example, by deleting the line containing move(coin)), a bytecode validation error will be raised. This protects Move programmers from accidental or malicious loss of funds.

Currency module

Each account can contain 0 or more modules (depicted as rectangles) and one or more resource values (depicted as cylinders). For example, the account at address 0x0 contains the module 0x0.Currency and a resource value of type 0x0.Currency.Coin. The account at address 0x1 has two resources and one module; The account at address 0x2 has two modules and one resource value.

Some moments:

  • The transaction script is atomic - either completely executed, or not at all.
  • A module is a long-lived piece of code that is globally available.
  • The global state is structured as a hash table, where the account address is the key
  • Accounts can contain no more than one resource value of a given type and no more than one module with a given name (an account at address 0x0 cannot contain an additional resource 0x0.Currency.Coin or another module named Currency)
  • The address of the module being declared is part of the type (0x0.Currency.Coin and 0x1.Currency.Coin are separate types that cannot be used interchangeably)
  • Programmers can store multiple instances of a given resource type in an account by defining their custom resource - (resource TwoCoins {c1: 0x0.Currency.Coin, c2: 0x0.Currency.Coin})
  • You can refer to a resource by its name without conflict, for example you can refer to two resources using TwoCoins.c1 and TwoCoins.c2.
2 Likes

Coin resource declaration

Module named Currency and resource type named Coin

Some moments:

  • Coin is a single field structure of type u64 (64-bit unsigned integer)
  • Only procedures in the Currency module can create or destroy values of type Coin.
  • Other modules and scripts can only write or refer to the value field through public procedures provided by the module.
2 Likes

Implementation of the deposit

This procedure takes a Coin resource as input and concatenates it with a Coin resource held in the recipient’s account:

  • Destroying the input resource Coin and writing its value.
  • Obtaining a link to a unique Coin resource stored on the recipient’s account.
  • Changing the value of the number of Coins by the value passed in the parameter when calling the procedure.

Some moments:

  • Unpack, BorrowGlobal - built-in procedures
  • Unpack is the only way to remove a resource of type T. The procedure takes a resource as input, destroys it, and returns the value associated with the fields of the resource.
  • BorrowGlobal takes an address as input and returns a reference to the unique T instance published (owned) by that address
2 Likes

&mut Coin is a link to a Coin resource

Implementing withdraw_from_sender

This procedure:
• Gets a link to a unique Coin resource linked to the sender’s account
• Decreases the value of the Coin resource by reference by the specified amount
• Creates and returns a new Coin resource with an updated balance.

Some moments:

• Deposit can be called by anyone, but withdraw_from_sender only has access to the calling account’s coins
• GetTxnSenderAddress is similar to msg.sender in Solidity
• RejectUnless is similar to require in Solidity. If this check fails, the execution of the transaction stops and all changes are rolled back.
• Pack is also a built-in procedure that creates a new resource of type T.
• Just like Unpack, Pack can only be called within the module where the resource T is declared.

2 Likes

Amazing work done here :star_struck:
A lot of interesting about Move
@james what do you think ?
Sergei is a day one member of our RU community channel by the way

2 Likes

It would be great if you could join our Fridays Russian - speaking workshops. Do you need link?

1 Like

YES! need link!

There will also be an event today

3 Likes

thanks bro!

3 Likes

What Abt d English version, for those of us that doesn’t understand Russian, nd want Aptos to move forward :fast_forward: :blush:

2 Likes

Click on the translate icon

3 Likes

Oh, ok
Thanks :+1: man :100:

2 Likes

Thank you mate for the facilitation

2 Likes

no problem! Easy info for people!

good job man :v:

1 Like