В этом руководстве подробно описано, как писать, скомпилировать, тестировать, публиковать и взаимодействовать с модулями Move на блокчейне Aptos. Шаги таковы:
- Написать, скомпилировать и протестировать Move-модуль.
- Публикация модуля Move в блокчейн Aptos
- Инициализировать ресурсы модуля Move и взаимодействовать с ними
Это руководство основано на вашей первой транзакции в качестве библиотеки для данного примера. Следующее руководство содержит код примера, который можно полностью загрузить ниже:
В этом руководстве мы сосредоточимся на hello_blockchain.ts
и повторно используем библиотеку first_transaction.ts
из предыдущего руководства.
Вы можете найти проект typescript здесь
Шаг 1. Напишите и протестируйте модуль Move
Шаг 1.1 Загрузите Aptos-core
Для простоты этого упражнения в Aptos-core есть каталог move-examples
, который позволяет легко создавать и тестировать модули Move без загрузки дополнительных ресурсов. Со временем мы расширим этот раздел, чтобы описать, как использовать инструменты Move для разработки.
А пока скачайте и подготовьте Aptos-core:
git clone https://github.com/aptos-labs/aptos-core.git
cd aptos-core
./scripts/dev_setup.sh
source ~/.cargo/env
git checkout origin/devnet
Установите утилиту командной строки Aptos. Узнайте больше об утилите командной строки Aptos
cargo install --git https://github.com/aptos-labs/aptos-core.git aptos
Шаг 1.2 Обзор модуля
В этом терминале измените содержимое каталогов на aptos-move/move-examples/hello_blockchain
. Сохраните это окно терминала до конца этого руководства - позже мы будем называть его "Окно Move". В этом разделе мы рассмотрим файл sources/hello_blockchain.move
.
Этот модуль позволяет пользователям создавать ресурс String
под своей учетной записью и устанавливать его. Пользователи могут устанавливать только свой ресурс и не могут устанавливать чужие ресурсы.
module HelloBlockchain::Message {
use std::string;
use std::error;
use std::signer;
struct MessageHolder has key {
message: string::String,
}
public entry fun set_message(account: signer, message_bytes: vector<u8>)
acquires MessageHolder {
let message = string::utf8(message_bytes);
let account_addr = signer::address_of(&account);
if (!exists<MessageHolder>(account_addr)) {
move_to(&account, MessageHolder {
message,
})
} else {
let old_message_holder = borrow_global_mut<MessageHolder>(account_addr);
old_message_holder.message = message;
}
}
}
В приведенном выше коде две важные секции - это структура MessageHolder
и функция set_message
. set_message
- это script
функция, позволяющая вызывать ее непосредственно транзакциями. При ее вызове функция определяет, есть ли у текущей учетной записи ресурс MessageHolder
, и создает и сохраняет message
, если его нет. Если ресурс существует, message
в MessageHolder
перезаписывается.
Шаг 1.3 Тестирование модуля
Move позволяет проводить встроенные тесты, поэтому мы добавляем get_message
для удобства получения message
и тестовую функцию sender_can_set_message
для проверки end-to-end процесса . Это можно проверить, запустив cargo test
. В папке sources/hello_blockchain_test.move
есть еще один тест, который демонстрирует другой метод написания тестов.
Его можно проверить, введя в терминале команду cargo test test test_hello_blockchain -p move-examples -- --exact
.
Примечание: sender_can_set_message
- это script
функция для вызова script
функции set_message
.
const ENO_MESSAGE: u64 = 0;
public fun get_message(addr: address): string::String acquires MessageHolder {
assert!(exists<MessageHolder>(addr), Errors::not_published(ENO_MESSAGE));
*&borrow_global<MessageHolder>(addr).message
}
#[test(account = @0x1)]
public(script) fun sender_can_set_message(account: signer) acquires MessageHolder {
let addr = Signer::address_of(&account);
set_message(account, b"Hello, Blockchain");
assert!(
get_message(addr) == string::utf8(b"Hello, Blockchain"),
0
);
}
Шаг 2. Публикация и взаимодействие с модулем Move
Теперь мы возвращаемся к нашему приложению, чтобы развернуть модуль на блокчейне Aptos и взаимодействовать с ним. Как упоминалось ранее, это руководство основывается на предыдущем руководстве и использует общий код. В результате в этом руководстве обсуждаются только новые возможности этой библиотеки, включая возможность публикации, отправку транзакции set_message
и чтение MessageHolder::message
. Единственным отличием от публикации модуля и отправки транзакции является тип полезной нагрузки. См. следующее:
Шаг 2.1 Публикация модуля Move
const client = new AptosClient(NODE_URL);
const faucetClient = new FaucetClient(NODE_URL, FAUCET_URL);
/** Publish a new module to the blockchain within the specified account */
export async function publishModule(accountFrom: AptosAccount, moduleHex: string): Promise<string> {
const moduleBundlePayload = new TxnBuilderTypes.TransactionPayloadModuleBundle(
new TxnBuilderTypes.ModuleBundle([new TxnBuilderTypes.Module(new HexString(moduleHex).toUint8Array())]),
);
const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
client.getAccount(accountFrom.address()),
client.getChainId(),
]);
const rawTxn = new TxnBuilderTypes.RawTransaction(
TxnBuilderTypes.AccountAddress.fromHex(accountFrom.address()),
BigInt(sequenceNumber),
moduleBundlePayload,
1000n,
1n,
BigInt(Math.floor(Date.now() / 1000) + 10),
new TxnBuilderTypes.ChainId(chainId),
);
const bcsTxn = AptosClient.generateBCSTransaction(accountFrom, rawTxn);
const transactionRes = await client.submitSignedBCSTransaction(bcsTxn);
return transactionRes.hash;
}
СОВЕТ
Для инициализации модуля можно написать функциюinit_module
. Эта приватная функция выполняется автоматически при публикации модуля. Эта функцияinit_module
должна быть приватной, принимать в качестве параметра только signer или ссылку на signer и не возвращать никакого значения. Вот пример:fun init_module(creator: &signer) { move_to( creator, ModuleData { global_counter: 0 } ); }
Шаг 2.2 Чтение ресурса
Модуль публикуется по адресу. Ниже приведен адрес contract_address
. Это похоже на предыдущий пример, где Coin
находится по адресу 0x1
. Адрес contract_address
будет таким же, как и у учетной записи, которая его публикует.
/** Retrieve the resource Message::MessageHolder::message */
async function getMessage(contractAddress: HexString, accountAddress: MaybeHexString): Promise<string> {
try {
const resource = await client.getAccountResource(
accountAddress,
`${contractAddress.toString()}::message::MessageHolder`,
);
return (resource as any).data["message"];
} catch (_) {
return "";
}
}
Шаг 2.3 Изменение ресурса
Модули Move должны раскрывать функции script
для инициализации и управления ресурсами. Затем script
может быть вызван из транзакции.
Примечание: хотя интерфейс REST может отображать строки, из-за ограничений JSON и Move он не может определить, является ли аргумент строкой или строкой в шестнадцатеричном коде. Поэтому аргументы транзакции всегда предполагают последнее. Следовательно, в данном примере сообщение закодировано как шестнадцатеричная строка.
/** Potentially initialize and set the resource Message::MessageHolder::message */
async function setMessage(contractAddress: HexString, accountFrom: AptosAccount, message: string): Promise<string> {
const entryFunctionPayload = new TxnBuilderTypes.TransactionPayloadEntryFunction(
TxnBuilderTypes.EntryFunction.natural(
`${contractAddress.toString()}::message`,
"set_message",
[],
[BCS.bcsSerializeStr(message)],
),
);
const [{ sequence_number: sequenceNumber }, chainId] = await Promise.all([
client.getAccount(accountFrom.address()),
client.getChainId(),
]);
const rawTxn = new TxnBuilderTypes.RawTransaction(
TxnBuilderTypes.AccountAddress.fromHex(accountFrom.address()),
BigInt(sequenceNumber),
entryFunctionPayload,
1000n,
1n,
BigInt(Math.floor(Date.now() / 1000) + 10),
new TxnBuilderTypes.ChainId(chainId),
);
const bcsTxn = AptosClient.generateBCSTransaction(accountFrom, rawTxn);
const transactionRes = await client.submitSignedBCSTransaction(bcsTxn);
return transactionRes.hash;
}
Шаг 3. Инициализация и взаимодействие с модулем Move
Для Typescript:
- Загрузите пример проекта
- Откройте ваш любимый терминал и перейдите туда, где вы скачали вышеупомянутый пример проекта
- Установите необходимые библиотеки:
yarn install
- Выполните пример:
yarn hello_blockchain Message.mv
- Через несколько мгновений появится сообщение: "Обновить модуль с адресом Alice, собрать, скопировать в указанный путь и нажать enter."
В терминале "Окно Move" и для файла Move, который мы рассматривали ранее:
Скопировать адрес Alice.
Скомпилируйте модули с адресом Alice командой
aptos move compile --package-dir . --named-addresses hello_blockchain=0x{alice_address_here}
. Здесь мы заменяем общий именованный адресhello_blockchain='_'
вhello_blockchain/move.toml
на адрес AliceСкопируйте
build/Examples/bytecode_modules/Message.mv
в ту же папку, что и код данного руководства проекта.Вернитесь в другое окно терминала и нажмите "enter" в подсказке, чтобы продолжить выполнение остальной части кода
Вывод должен выглядеть следующим образом:
=== Addresses ===
Alice: 11c32982d04fbcc79b694647edff88c5b5d5b1a99c9d2854039175facbeefb40
Bob: 7ec8f962139943bc41c17a72e782b7729b1625cf65ed7812152a5677364a4f88
=== Initial Balances ===
Alice: 10000000
Bob: 10000000
Update the module with Alice's address, build, copy to the provided path, and press enter.
=== Testing Alice ===
Publishing...
Initial value: None
Setting the message to "Hello, Blockchain"
New value: Hello, Blockchain
=== Testing Bob ===
Initial value: None
Setting the message to "Hello, Blockchain"
New value: Hello, Blockchain
Результат показывает, что Alice и Bob прошли путь от отсутствия ресурса до ресурса с message
"Hello, Blockchain".
Данные можно проверить, посетив либо REST-интерфейс, либо Explorer:
- Учетная запись Alice's через интерфейс Aptos REST.
- Учетная запись Bob's через Aptos Explorer.
Top comments (0)