DEV Community

EgorMajj
EgorMajj

Posted on

Руководство для разработчиков APTOS | Ваш первый модуль MOVE | Typescript

В этом руководстве подробно описано, как писать, скомпилировать, тестировать, публиковать и взаимодействовать с модулями Move на блокчейне Aptos. Шаги таковы:

  1. Написать, скомпилировать и протестировать Move-модуль.
  2. Публикация модуля Move в блокчейн Aptos
  3. Инициализировать ресурсы модуля 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
Enter fullscreen mode Exit fullscreen mode

Установите утилиту командной строки Aptos. Узнайте больше об утилите командной строки Aptos

cargo install --git https://github.com/aptos-labs/aptos-core.git aptos
Enter fullscreen mode Exit fullscreen mode

Шаг 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;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

В приведенном выше коде две важные секции - это структура 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
        );
    }
Enter fullscreen mode Exit fullscreen mode

Шаг 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;
}
Enter fullscreen mode Exit fullscreen mode

СОВЕТ
Для инициализации модуля можно написать функцию 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 "";
  }
}
Enter fullscreen mode Exit fullscreen mode

Шаг 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;
}
Enter fullscreen mode Exit fullscreen mode

Шаг 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

Enter fullscreen mode Exit fullscreen mode

Результат показывает, что Alice и Bob прошли путь от отсутствия ресурса до ресурса с message "Hello, Blockchain".

Данные можно проверить, посетив либо REST-интерфейс, либо Explorer:

  • Учетная запись Alice's через интерфейс Aptos REST.
  • Учетная запись Bob's через Aptos Explorer.

Top comments (0)