Ваш первый Move модуль
В этом руководстве подробно рассказывается, как писать, компилировать, тестировать, публиковать и взаимодействовать с модулями Move в Aptos Blockchain. Мы рассмотрим следующие шаги:
Напишите, скомпилируйте и протестируйте модуль Move.
Опубликуйте модуль Move в Aptos Blockchain.
Запустите и взаимодействуйте с ресурсами Move Module.
Это руководство основано на разделе Ваша первая транзакция в качестве библиотеки для этого примера. Данное руководство содержит пример кода, который можно полностью загрузить:
В этом руководстве основное внимание будет уделено hello_blockchain.py и повторному использованию библиотеки first_transaction.py из предыдущего руководства.
Вы найдете python project здесь.
В этом руководстве основное внимание будет уделено hello_blockchain.rs и повторному использованию библиотеки first_transaction.rs из предыдущего руководства.
Вы найдете rust project здесь.
В этом руководстве основное внимание будет уделено hello_blockchain.ts и повторному использованию библиотеки first_transaction.ts из предыдущего руководства.
Вы найдете typescript project здесь.
Шаг 1) Напишите и протестируйте Move Module
Шаг 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 Commandline tool. Узнайте больше по ссылке Aptos command line tool.
cargo install --git https://github.com/aptos-labs/aptos-core.git aptosШаг 1.2) Просмотрите модуль
В этом терминале измените каталоги наaptos-move/move-examples/hello_blockchain. Сохраните окно терминала до конца данного руководства — далее мы будем называть его "Move Window". В оставшейся части этого раздела будет рассмотрен файл sources/HelloBlockchain.move.
Этот модуль позволяет пользователям создать и установить ресурс String под своей учетной записью. Пользователи могут устанавливать только свой ресурс и не могут устанавливать ресурсы других.
module HelloBlockchain::Message {
use Std::ASCII;
use Std::Errors;
use Std::Signer;
struct MessageHolder has key {
message: ASCII::String,
}
public(script) fun set_message(account: signer, message_bytes: vector<u8>)
acquires MessageHolder {
let message = ASCII::string(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 для проверки сквозного потока. Это можно проверить, запустив cargo test. Есть еще один тест sources/HelloBlockchainTest.move , демонстрирующий другой метод написания тестов.
Это можно проверить, введя на терминале cargo 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): ASCII::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) == ASCII::string(b"Hello, Blockchain"),
0
);
}Шаг 2) Публикация и взаимодействие с Move Module
Теперь вернемся к нашему приложению для развертывания и взаимодействия с модулем в блокчейне Atpos. Как упоминалось ранее, это руководство основано на предыдущем руководстве и использует общий код. Соответственно, в этом руководстве обсуждаются только новые функции данной библиотеки, включая возможность публикации, отправки транзакцииset_message и чтения MessageHolder::message. Единственное отличие от публикации модуля и отправки транзакции — это тип полезной нагрузки. См. следующее:
Шаг 2.1) Публикация Move Module
class HelloBlockchainClient(RestClient):
def publish_module(self, account_from: Account, module_hex: str) -> str:
"""Publish a new module to the blockchain within the specified account"""
payload = {
"type": "module_bundle_payload",
"modules": [
{"bytecode": f"0x{module_hex}"},
],
}
txn_request = self.generate_transaction(account_from.address(), payload)
signed_txn = self.sign_transaction(account_from, txn_request)
res = self.submit_transaction(signed_txn)
return str(res["hash"])pub struct HelloBlockchainClient {
pub rest_client: RestClient,
}
impl HelloBlockchainClient {
/// Represents an account as well as the private, public key-pair for the Aptos blockchain.
pub fn new(url: String) -> Self {
Self {
rest_client: RestClient::new(url),
}
}
/// Publish a new module to the blockchain within the specified account
pub fn publish_module(&self, account_from: &mut Account, module_hex: &str) -> String {
let payload = serde_json::json!({
"type": "module_bundle_payload",
"modules": [{"bytecode": format!("0x{}", module_hex)}],
});
self.rest_client.execution_transaction_with_payload(account_from, payload)
}
export class HelloBlockchainClient extends RestClient {
/** Publish a new module to the blockchain within the specified account */
async publishModule(accountFrom: Account, moduleHex: string): Promise<string> {
const payload = {
type: "module_bundle_payload",
modules: [{ bytecode: `0x${moduleHex}` }],
};
const txnRequest = await this.generateTransaction(accountFrom.address(), payload);
const signedTxn = await this.signTransaction(accountFrom, txnRequest);
const res = await this.submitTransaction(signedTxn);
return res["hash"];
}
Шаг 2.2) Чтение ресурса
Модуль публикуется по адресу. Ниже приведен адрес contract_address . Это похоже на предыдущий пример, где монетаCoin находится по адресу 0x1. contract_address будет таким же, как у учетной записи, которая его публикует.
def get_message(self, contract_address: str, account_address: str) -> Optional[str]:
""" Retrieve the resource Message::MessageHolder::message """
return self.account_resource(account_address, f"0x{contract_address}::Message::MessageHolder") /// Retrieve the resource Message::MessageHolder::message
pub fn get_message(&self, contract_address: &str, account_address: &str) -> Option<String> {
let module_type = format!("0x{}::Message::MessageHolder", contract_address);
self.rest_client
.account_resource(account_address, &module_type)
.map(|value| value["data"]["message"].as_str().unwrap().to_string())
}
/** Retrieve the resource Message::MessageHolder::message */
async getMessage(contractAddress: string, accountAddress: string): Promise<string> {
const resource = await this.accountResource(accountAddress, `0x${contractAddress}::Message::MessageHolder`);
if (resource == null) {
return null;
} else {
return resource["data"]["message"];
}
}
Шаг 2.3) Изменение ресурса
Модули Move должны раскрывать функции script для запуска и управления ресурсами. Затем script можно вызвать из транзакции.
Примечание: хотя интерфейс REST и может отображать строки, но из-за ограничений JSON и Move он не может определить, является ли аргумент строкой или строкой в шестнадцатеричном коде. Таким образом, аргументы транзакции всегда предполагают последнее. Следовательно, в этом примере сообщение закодировано как шестнадцатеричная строка.
def set_message(self, contract_address: str, account_from: Account, message: str) -> str:
""" Potentially initialize and set the resource Message::MessageHolder::message """
payload = {
"type": "script_function_payload",
"function": f"0x{contract_address}::Message::set_message",
"type_arguments": [],
"arguments": [
message.encode("utf-8").hex(),
]
}
res = self.execute_transaction_with_payload(account_from, payload)
return str(res["hash"]) /// Potentially initialize and set the resource Message::MessageHolder::message
pub fn set_message(
&self,
contract_address: &str,
account_from: &mut Account,
message: &str,
) -> String {
let message_hex = hex::encode(message.as_bytes());
let payload = serde_json::json!({
"type": "script_function_payload",
"function": format!("0x{}::Message::set_message", contract_address),
"type_arguments": [],
"arguments": [message_hex]
});
self.rest_client.execution_transaction_with_payload(account_from, payload)
}
/** Potentially initialize and set the resource Message::MessageHolder::message */
async setMessage(contractAddress: string, accountFrom: Account, message: string): Promise<string> {
let payload: { function: string; arguments: string[]; type: string; type_arguments: any[] };
payload = {
type: "script_function_payload",
function: `0x${contractAddress}::Message::set_message`,
type_arguments: [],
arguments: [Buffer.from(message, "utf-8").toString("hex")],
};
const txnRequest = await this.generateTransaction(accountFrom.address(), payload);
const signedTxn = await this.signTransaction(accountFrom, txnRequest);
const res = await this.submitTransaction(signedTxn);
return res["hash"];
}
}Шаг 3) Запуск и взаимодействие с Move module
Для Python3:
Загрузите example project.
Откройте свой любимый терминал и перейдите туда, куда вы загрузили приведенный выше example project.
Установите необходимые библиотеки:
pip3 install -r requirements.txt.Выполните:
python3 hello_blockchain.py Message.mv
Для Rust:
Загрузите example project.
Откройте свой любимый терминал и перейдите туда, куда вы загрузили приведенный выше example project.
Выполните:
cargo run --bin hello-blockchain -- Message.mv
Для Typescript:
Загрузите example project.
Откройте свой любимый терминал и перейдите туда, куда вы загрузили приведенный выше example project.
Установите необходимые библиотеки:
yarn installВыполните:
yarn hello_blockchain Message.mv
Через некоторое время появится сообщение: "Обновите модуль с адресом Алисы, создайте, скопируйте по указанному пути и нажмите Enter."
В терминале "Move Window" и для файла Move, который мы ранее рассматривали:
Скопируйте адрес Алисы
Скомпилируйте модули с адресом Алисы с помощью
aptos move compile --package-dir . --named-addresses HelloBlockchain=0x{alice_address_here}. Здесь бы заменяем общий адресHelloBlockChain='_'вhello_blockchain/move.tomlна адрес АлисыСкопируйте
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Результат показывает, что Алиса и Боб перешли от отсутствия ресурсов к одному с message "Hello, Blockchain".
Данные можно проверить, посетив либо интерфейс REST, либо :
Учетная запись Алисы через REST interface
Учетная запись Боба на explorer
Last updated