С запуском основной сети Aptos 18 октября, язык программирования Move и его экосистема продолжают расширять свое влияние. Чтобы привлечь сообщество, мы выпустим серию статей, посвященных методам безопасной разработки на Move. Мы погрузим вас в мир Move с помощью примеров, объяснений и, что самое важное, методов обеспечения безопасности.
TL;DR
В этой статье рассказывается:
- как создать и разработать приложение для Aptos;
- как выглядит модуль (т.е. смарт-контракт в Move);
- как скомпилировать и опубликовать модуль в локальной сети;
- как взаимодействовать с модулем и проверить выведенное событие в браузере.
0x1. О Move и его экосистеме
Move — это наследник Diem (прежнее название — Libra до декабря 2020 года), разработанный для создания смарт-контрактов. Он позиционируется как безопасный, быстрый и гибкий язык, претендующий на звание языка следующего поколения. Однако новые проекты, такие как Aptos и Sui, не используют оригинальный Move напрямую, внося определенные изменения для соответствия своим потребностям.
Если не указано иное, мы сосредоточимся на методах разработки в контексте Aptos, так как эти идеи применимы и для других проектов на базе Move. Мы также предполагаем, что вы уже изучили MoveBook для получения базовых знаний о языке программирования Move.
0x2. Подготовка окружения
0x2.1 Инструментарий Aptos
В Aptos интеграция Move уже реализована в CLI. Поэтому рекомендуется следовать инструкции по установке CLI для установки соответствующего набора инструментов. После завершения установки введите aptos в терминале, и вы должны увидеть следующий вывод:
$ aptos
aptos 1.0.1
Aptos Labs <[email protected]>
Command Line Interface (CLI) for developing and interacting with the Aptos blockchain
USAGE:
aptos <SUBCOMMAND>
OPTIONS:
-h, --help Print help information
-V, --version Print version information
SUBCOMMANDS:
account Tool for interacting with accounts
config Tool for interacting with configuration of the Aptos CLI tool
genesis Tool for setting up an Aptos chain Genesis transaction
governance Tool for on-chain governance
help Print this message or the help of the given subcommand(s)
info Show build information about the CLI
init Tool to initialize current directory for the aptos tool
key Tool for generating, inspecting, and interacting with keys
move Tool for Move related operations
node Tool for operations related to nodes
stake Tool for manipulating stake and stake pools
0x2.2 Локальная тестовая сеть и аккаунт
Aptos предоставляет несколько сетей (основная сеть, тестовая сеть, devnet и локальная тестовая сеть) для разработки и развертывания. В этой статье мы будем использовать локальную тестовую сеть.
Для запуска локальной тестовой сети введите следующую команду:
$ aptos node run-local-testnet --with-faucet --force-restart
Вы должны увидеть следующий вывод:
......
Aptos is running, press ctrl-c to exit
Faucet is running. Faucet endpoint: 0.0.0.0:8081
Теперь вы можете создать свой аккаунт, введя следующую команду (возможно, в другом окне терминала, если хотите оставить предыдущее окно работающим):
$ aptos init
Эта команда откроет интерактивную оболочку, в которой необходимо указать некоторые параметры. Мы выбираем сеть local. После этого в текущей директории появится папка .aptos с конфигурацией вашего аккаунта по умолчанию. Проверьте содержимое файла и скопируйте адрес вашего account (например, c0d8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx14bd).
Совет №1: Храните файл конфигурации аккаунта в безопасности! Ваш закрытый ключ (private key) записан в нем!
0x3. Первая программа Hello World
Программа Hello World всегда используется как первый шаг в изучении написания кода. Мы будем следовать этой традиции, чтобы продемонстрировать способ разработки приложений на Move.
0x3.1 Подготовка пакета
Выберите нужную директорию и введите следующую команду:
$ aptos move init --framework-local-dir "../../aptos-core/aptos-move/framework/aptos-framework" --name hello
Эта команда создаст новый пакет Move в указанном месте (т.е. в рабочем пространстве разработки). Поскольку некоторые библиотечные функции инфраструктуры Aptos необходимы, указывается локальная директория фреймворка Aptos (относительный путь может меняться в зависимости от другого расположения); альтернативно можно указать git-ревизию или ветку для фреймворка Aptos с помощью --framework-git-rev.
Теперь вы увидите файл Move.toml в вашей директории. Этот файл не только перечисляет конфигурации зависимостей, но и описывает имя и версию пакета. Кроме того, существует папка sources, которая используется для хранения исходного кода Move. После создания файла .move в директории sources рабочее пространство готово к использованию.
[package]
name = 'hello'
version = '1.0.0'
[dependencies.AptosFramework]
local = '../../aptos-core/aptos-move/framework/aptos-framework'
[addresses]
BlockSec="c0d8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx14bd"
В последней строке Move.toml мы связываем адрес аккаунта (созданный ранее) с BlockSec. Он используется для публикации модуля (т.е. развертывания смарт-контракта) в этом пакете (будет рассмотрено позже). Обратите внимание, что указанный выше адрес является лишь заполнителем, и вы ДОЛЖНЫ заменить его на адрес своего собственного аккаунта.
0x3.2 Подготовка модуля
Ниже представлен простой, но полноценный пример модуля, который можно напрямую добавить в файл .move (например, hello.move). Далее мы разберем код, чтобы проиллюстрировать отличия Move от других языков программирования. Вы можете пропустить этот раздел, если уже хорошо с ними знакомы.
module BlockSec::hello{
use aptos_framework::account;
use aptos_framework::event;
use std::signer;
use std::string::{String, utf8};
struct SecEventStore has key{
event_handle: event::EventHandle<String>,
}
public entry fun say_hello_script(account: &signer) acquires SecEventStore{
say_hello(account);
}
public fun say_hello(account: &signer) acquires SecEventStore{
let address_ = signer::address_of(account);
if(!exists<SecEventStore>(address_)){
move_to(account, SecEventStore{event_handle: account::new_event_handle(account)});
};
event::emit_event<String>(&mut borrow_global_mut<SecEventStore>(address_).event_handle, utf8(b"Hello World!"));
}
}
Здесь мы определяем модуль с именем hello, который будет опубликован по адресу BlockSec. Точка входа в этот модуль называется say_hello_script, которая вызывает функцию say_hello. Легко понять, что этот модуль используется для генерации события с сообщением "Hello World!" (в функции say_hello). Однако все еще есть некоторые детали, которые необходимо прояснить.
В частности, чтобы использовать функцию event::emit_event в пространстве имен aptos_framework, нам нужна структура event::EventHandle, так как функция emit_event имеет следующее объявление:
/// Emit an event with payload `msg` by using `handle_ref`'s key and counter.
public fun emit_event<T: drop + store>(handle_ref: &mut EventHandle<T>, msg: T)
struct EventHandle<phantom T: drop + store> has store {
/// Total number of events emitted to this event stream.
counter: u64,
/// A globally unique ID for this event stream.
guid: GUID,
}
Обратите внимание, что EventHandle не имеет способности (ability) key, что означает, что мы должны хранить его в другой структуре. Следовательно, мы определяем структуру SecEventStore для хранения EventHandle:
struct SecEventStore has key{
event_handle: event::EventHandle<String>,
}
Совет №2: Мы должны учитывать способности структуры в Move. Помните, что только способность
**_key_**может быть использована в**_move_to_**. Если модуль возвращает структуру, у которой есть только способность**_store_**, и вы хотите сохранить её в глобальном хранилище, рассмотрите возможность определения новой структуры в качестве обертки.
Для простоты мы используем String для представления сообщения. Итак, финальный шаг функции say_hello:
event::emit_event<String>(&mut borrow_global_mut<SecEventStore>(address_).event_handle, utf8(b"Hello World!"));
Совет №3: Move не поддерживает тип
**_String_**нативно. Стандартная библиотека предоставляет возможность преобразования вектора байтов в**_String_**. Подробности можно найти в исходном коде в их репозитории на GitHub.
Чтобы гарантировать, что каждый новый пользователь зарегистрирован с SecEventStore, нам нужно сначала проверить существование структуры в аккаунте пользователя с помощью функции exists. Если у пользователя нет этого ресурса, функция его создаст и переместит в аккаунт пользователя.
if(!exists<SecEventStore>(address_)){
move_to(account, SecEventStore{event_handle: account::new_event_handle(account)});
};
0x3.3 Компиляция и публикация модуля
Когда модуль готов, мы можем скомпилировать его следующей командой:
$ aptos move compile
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING hello
{
"Result": [
"c0d8xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx14bd::hello"
]
}
При необходимости мы можем протестировать его:
$ aptos move test
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING hello
Running Move unit tests
Test result: OK. Total tests: 0; passed: 0; failed: 0
{
"Result": "Success"
}
Теперь мы можем развернуть модуль в сети Aptos. Помните, что мы связали аккаунт с BlockSec, потому что пользователь может публиковать модули только в аккаунты, находящиеся под его контролем. Кроме того, кран (faucet) уже пополнил аккаунт некоторым количеством APT для оплаты комиссий за газ. Осталось только опубликовать модуль из пакета Move в сеть Aptos:
$ aptos move publish --package-dir ./ --profile default
Compiling, may take a little while to download git dependencies...
INCLUDING DEPENDENCY AptosFramework
INCLUDING DEPENDENCY AptosStdlib
INCLUDING DEPENDENCY MoveStdlib
BUILDING hello
package size 1271 bytes
Do you want to submit a transaction for a range of [672200 - 1008300] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
"Result":
...
}
Снова появляется интерактивная оболочка, а содержимое Result здесь опущено.
0x3.4 Взаимодействие с модулем
Чтобы заставить модуль сгенерировать событие, просто введите следующую команду:
$ aptos move run --function-id default::hello::say_hello_script
Do you want to submit a transaction for a range of [34500 - 51700] Octas at a gas unit price of 100 Octas? [yes/no] >
yes
{
"Result": {
"transaction_hash": "0x9af16532de5e79803c823fe28e3251703927d93809274b76972d8e83c6fcd433",
...
}
}
Как entry-функцию, say_hello_script можно вызывать напрямую. Вы также можете написать скрипт и вызвать функцию say_hello внутри него.
Совет №4: Для лучшего взаимодействия хорошей практикой является определение нескольких entry-функций. Вы также можете разрабатывать скрипты для пользователей, чтобы они могли взаимодействовать с вашим проектом.
В отличие от традиционной программы Web2 Hello World, сгенерированное событие не будет отображаться в консоли. Зайдите в Aptos explorer и выберите сеть local.

Затем скопируйте значение transaction_hash из терминала, вставьте его в строку поиска, и вы увидите детали транзакции.

Наконец, нажмите на Events, и сеть Aptos поприветствует вас.

0x4. Что дальше?
Программа Hello World — это лишь небольшой шаг в разработке приложений на Move. В следующих статьях этой серии мы расскажем больше о разработке безопасных приложений на Move в Aptos. Оставайтесь с нами!
О компании BlockSec
BlockSec — это передовая компания в области безопасности блокчейнов, основанная в 2021 году группой выдающихся мировых экспертов по безопасности. Компания стремится повысить уровень безопасности и удобства использования для развивающегося мира Web3, чтобы способствовать его массовому внедрению. Для этого BlockSec предоставляет услуги по аудиту безопасности смарт-контрактов и EVM-сетей, платформу Phalcon для безопасной разработки и проактивного блокирования угроз, платформу MetaSleuth для отслеживания средств и расследований, а также расширение MetaSuites для эффективного серфинга в криптомире.
На сегодняшний день компания обслужила более 300 уважаемых клиентов, таких как MetaMask, Uniswap Foundation, Compound, Forta и PancakeSwap, и привлекла десятки миллионов долларов США в двух раундах финансирования от ведущих инвесторов, включая Matrix Partners, Vitalbridge Capital и Fenbushi Capital.
Официальный сайт: https://blocksec.com/
Официальный аккаунт в Twitter: https://twitter.com/BlockSecTeam



