> For the complete documentation index, see [llms.txt](https://cr-nepos.gitbook.io/aptos-ru/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cr-nepos.gitbook.io/aptos-ru/rukovodstva-po-primeneniyu/vash-pervyi-move-modul.md).

# Ваш первый Move модуль

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

1. Напишите, скомпилируйте и протестируйте модуль Move.
2. Опубликуйте модуль Move в Aptos Blockchain.
3. Запустите и взаимодействуйте с ресурсами Move Module.

Это руководство основано на разделе [Ваша первая транзакция](/aptos-ru/rukovodstva-po-primeneniyu/vasha-pervaya-tranzakciya.md) в качестве библиотеки для этого примера. Данное руководство содержит пример кода, который можно полностью загрузить:

{% tabs %}
{% tab title="Python" %}
В этом руководстве основное внимание будет уделено `hello_blockchain.py` и повторному использованию библиотеки `first_transaction.py` из предыдущего руководства.

Вы найдете python project [здесь](https://github.com/aptos-labs/aptos-core/tree/main/developer-docs-site/static/examples/python).
{% endtab %}

{% tab title="Rust" %}
В этом руководстве основное внимание будет уделено `hello_blockchain.rs` и повторному использованию библиотеки `first_transaction.rs` из предыдущего руководства.

Вы найдете rust project [здесь](https://github.com/aptos-labs/aptos-core/tree/main/developer-docs-site/static/examples/rust).
{% endtab %}

{% tab title="Typescript" %}
В этом руководстве основное внимание будет уделено `hello_blockchain.ts` и повторному использованию библиотеки `first_transaction.ts` из предыдущего руководства.

Вы найдете typescript project [здесь](https://github.com/aptos-labs/aptos-core/tree/main/developer-docs-site/static/examples/typescript).
{% endtab %}
{% endtabs %}

### Шаг 1) Напишите и протестируйте Move Module <a href="#step-1-write-and-test-the-move-module" id="step-1-write-and-test-the-move-module"></a>

#### Шаг 1.1) Загрузите Aptos-core <a href="#step-11-download-aptos-core" id="step-11-download-aptos-core"></a>

Для простоты выполнения этой задачи в Aptos-core имеется каталог `move-examples` , который позволяет легко создавать и тестировать модули Move без загрузки дополнительных ресурсов. Со временем мы расширим этот раздел, чтобы описать, как использовать для разработки инструменты [Move](https://github.com/move-language/move/tree/main/language/documentation/tutorial).

А пока скачайте и подготовьте 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](https://github.com/aptos-labs/aptos-core/tree/main/crates/aptos).

```
cargo install --git https://github.com/aptos-labs/aptos-core.git aptos
```

#### Шаг 1.2) Просмотрите модуль <a href="#step-12-review-the-module" id="step-12-review-the-module"></a>

В этом терминале измените каталоги на`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) Тестирование модуля <a href="#step-13-testing-the-module" id="step-13-testing-the-module"></a>

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 <a href="#step-2-publishing-and-interacting-with-the-move-module" id="step-2-publishing-and-interacting-with-the-move-module"></a>

Теперь вернемся к нашему приложению для развертывания и взаимодействия с модулем в блокчейне Atpos. Как упоминалось ранее, это руководство основано на предыдущем руководстве и использует общий код. Соответственно, в этом руководстве обсуждаются только новые функции данной библиотеки, включая возможность публикации, отправки транзакции`set_message` и чтения `MessageHolder::message`. Единственное отличие от публикации модуля и отправки транзакции — это тип полезной нагрузки. См. следующее:

#### Шаг 2.1) Публикация Move Module <a href="#step-21-publishing-the-move-module" id="step-21-publishing-the-move-module"></a>

{% tabs %}
{% tab title="Python" %}

```
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"])
```

{% endtab %}

{% tab title="Rust" %}

```
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)
    }
    
```

{% endtab %}

{% tab title="Typescript" %}

```
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"];
  }
  
```

{% endtab %}
{% endtabs %}

#### Шаг 2.2) Чтение ресурса <a href="#step-22-reading-a-resource" id="step-22-reading-a-resource"></a>

Модуль публикуется по адресу. Ниже приведен адрес `contract_address` . Это похоже на предыдущий пример, где монета`Coin` находится по адресу `0x1`.  `contract_address` будет таким же, как у учетной записи, которая его публикует.

{% tabs %}
{% tab title="Python" %}

```
  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")
```

{% endtab %}

{% tab title=" Rust" %}

```
    /// 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())
    }

    
```

{% endtab %}

{% tab title=" Typescript" %}

```
  /** 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"];
    }
  }
  
```

{% endtab %}
{% endtabs %}

#### Шаг 2.3) Изменение ресурса <a href="#step-23-modifying-a-resource" id="step-23-modifying-a-resource"></a>

Модули Move должны раскрывать функции `script` для запуска и управления ресурсами. Затем `script` можно вызвать из транзакции.

Примечание: хотя интерфейс REST и может отображать строки, но из-за ограничений JSON и Move он не может определить, является ли аргумент строкой или строкой в шестнадцатеричном коде. Таким образом, аргументы транзакции всегда предполагают последнее. Следовательно, в этом примере сообщение закодировано как шестнадцатеричная строка.

{% tabs %}
{% tab title="Python" %}

```
    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"])
```

{% endtab %}

{% tab title="Rust" %}

```
    /// 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)
    }
    
```

{% endtab %}

{% tab title="Typescript" %}

```
  /**  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"];
  }
}
```

{% endtab %}
{% endtabs %}

#### Шаг 3) Запуск и взаимодействие с Move module <a href="#step-3-initialize-and-interact-with-the-move-module" id="step-3-initialize-and-interact-with-the-move-module"></a>

{% tabs %}
{% tab title="Python" %}
Для Python3:

* Загрузите [example project](https://github.com/aptos-labs/aptos-core/tree/main/developer-docs-site/static/examples/python).
* Откройте свой любимый терминал и перейдите туда, куда вы загрузили приведенный выше example project.
* Установите необходимые библиотеки: `pip3 install -r requirements.txt`.
* Выполните: `python3 hello_blockchain.py Message.mv`
  {% endtab %}

{% tab title="Rust" %}
Для Rust:

* Загрузите [example project](https://github.com/aptos-labs/aptos-core/tree/main/developer-docs-site/static/examples/rust).
* Откройте свой любимый терминал и перейдите туда, куда вы загрузили приведенный выше example project.
* Выполните: `cargo run --bin hello-blockchain -- Message.mv`
  {% endtab %}

{% tab title=" Typescript " %}
Для Typescript:

* Загрузите [example project](https://github.com/aptos-labs/aptos-core/tree/main/developer-docs-site/static/examples/typescript).

* Откройте свой любимый терминал и перейдите туда, куда вы загрузили приведенный выше example project.

* Установите необходимые библиотеки: `yarn install`

* Выполните: `yarn hello_blockchain Message.mv`
  {% endtab %}
  {% endtabs %}

* Через некоторое время появится сообщение: "Обновите модуль с адресом Алисы, создайте, скопируйте по указанному пути и нажмите 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](https://fullnode.devnet.aptoslabs.com/accounts/a52671f10dc3479b09d0a11ce47694c0/)
* Учетная запись Боба на [explorer](https://explorer.devnet.aptos.dev/account/ec6ec14e4abe10aaa6ad53b0b63a1806)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://cr-nepos.gitbook.io/aptos-ru/rukovodstva-po-primeneniyu/vash-pervyi-move-modul.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
