Стартовый пакет Aleo Development
Tags: aleo, instructions, install, privacy
Published: 2022-08-31 13:50:10

В этом посте мы сделаем обзор различных инструментов, доступных в Aleo SDK, чтобы начать разработку на Aleo.

Aleo SDK - это набор инструментов, который делает разработку на Aleo простой и удобной для разработчиков. С помощью этого инструмента вы можете создавать новые аккаунты, структуры (также известные как программы в экосистеме Aleo), создавать транзакции и отправлять их в сеть.

## 1. Настройка среды

Чтобы начать работать с Aleo, вам понадобится Aleo CLI, доступный в вашей среде. Вам также понадобится сборник rust (v1.62 или выше) для создания Aleo SDK. Если вы еще не установили его, просто запустите следующее в терминале:

```javascript
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
Если вам нужно только обновить версию rust, вы можете выполнить команду:

```javascript
rustup update stable
```

Вы должны обновить переменные среды, чтобы иметь возможность использовать Rust на данном этапе. Вы можете сделать это, просто закрыв терминал и открыв его снова.

Далее, чтобы установить Aleo SDK, запустите программу:

```javascript
# Download the source code
git clone https://github.com/AleoHQ/aleo && cd aleo

# Install Aleo
$ cargo install --path .
```

Теперь вы можете проверить, работает ли она:

```javascript
aleo -h
```
и вы должны увидеть следующий результат:

```javascript
aleo
The Aleo Team <hello@aleo.org>

USAGE:
    aleo [OPTIONS] <SUBCOMMAND>

OPTIONS:
    -h, --help                     Print help information
    -v, --verbosity <VERBOSITY>    Specify the verbosity [options: 0, 1, 2, 3] [default: 2]

SUBCOMMANDS:
    account    Commands to manage Aleo accounts
    build      Compiles an Aleo program
    clean      Cleans the Aleo package build directory
    help       Print this message or the help of the given subcommand(s)
    new        Create a new Aleo package
    node       Commands to operate a local development node
    run        Executes an Aleo program function
    update     Update Aleo
```

Легко и просто. Идем дальше.

## 2. Создание и построение простой программы

В этом шаге мы создадим простую программу Aleo для передачи наших собственных токенов. Для этого мы определим нашу собственную запись под названием token (базовая структура Aleo для работы с состоянием) и напишем функцию для передачи этих токенов между аккаунтами.

**Создание программы**

Давайте запустим новый проект Aleo:

```javascript
aleo new token
cd token
```
Это создаст наш шаблон для начала кодирования вашей новой программы Aleo под названием token.

Пока что мы заполним наш файл _main.aleo_ следующим кодом:

```javascript
// The 'token.aleo' program.
program token.aleo;

// Our own defined record called token
record token:
    owner as address.private;
    gates as u64.private;
    amount as u64.private;

// function to mint a new token
function mint_token:
    // token address
    input r0 as address.private;
    // token amount
    input r1 as u64.private;
    // password
    input r2 as field.private;

    // checks if the password is correct
    hash.psd2 r2 into r3;
    // it will continue running only is the password hashes match
    // the execution will fail otherwise.
    assert.eq r3 7202470996857839225873911078012225723419856133099120809866608931983814353616field;

    // create a new token in r2 register
    cast r0 0u64 r1 into r4 as token.record;
    // return the new token
    output r4 as token.record;

// Function to transfer tokens between accounts
function transfer_token:
    //  sender token record
    input r0 as token.record;
    // receiver address
    input r1 as address.private;
    // amount to transfer
    input r2 as u64.private;

    // final balance for sender
    sub r0.amount r2 into r3;
    // final balance for receiver
    add 0u64 r2 into r4;

    // sender token record after the transfer
    cast r0.owner r0.gates r3 into r5 as token.record;
    // receiver token record after the transfer
    cast r1 0u64 r4 into r6 as token.record;

    // sender new token record
    output r5 as token.record;
    // receiver new token record
    output r6 as token.record;
```
Эти строки кода называются инструкциями Aleo. Инструкции Aleo - это своего рода язык ассемблера для виртуальной машины Aleo snarkVM (виртуальная машина, на которой будут выполняться наши программы), но с довольно высокоуровневыми функциями, такими как система типизации, сложные инструкции для хеширования и так далее.

Подробнее об этих инструкциях вы можете прочитать в этом посте: Начало работы с инструкциями Aleo.

Давайте создадим нашу программу Aleo:

```javascript
aleo build
```

```javascript
⏳ Compiling 'token.aleo'...

 • Loaded universal setup (in 1459 ms)
 • Built 'transfer' (in 23549 ms)

✅ Built 'token.aleo' (in "/[...]/token")
```

> **Примечание:**
> Если вы впервые создаете программу Aleo, вам, вероятно, придется подождать, пока загрузится "universal setup". Не паникуйте, если в первый раз вы увидите другой результат!

После создания в каталоге /_build_ вы найдете 3 файла:

- _main.avm_: Файл, содержащий ваш скомпилированный код.
- 2 файла для каждой функции в вашем файле _main.aleo_:
- _function_name.prover_: провера для ваших функций
- _function_name.verifier_: верификатор для ваших функций

Эти файлы будут очень важны при развертывании нашего приложения.

## 3. Создание аккаунтов

Мы создадим два аккаунта Aleo для работы и осуществления переводов:

**Аккаунт S:**

```javascript
aleo account new
```

```javascript
  Private Key  APrivateKey1zkpAQpLeFgujVMkMEVKXhotR9XVa8B8nGfugMXYXHMdeHnN
     View Key  AViewKey1f6ZSnCkgsatCTDDSX5UgXXfjR14pyQ8oizxE5QGcWTxB
      Address  aleo1nmjzszxsejh0ec6s9tgdx03g24l8e3ev0jy6fx2ckz7s4vt7hgxqu8hz04
```
**Аккаунт R:**

```javascript
aleo account new
```

```javascript
  Private Key  APrivateKey1zkpFoVnVMTGvYKRALnzHkU9nKbMZ9Ueu9ZdsouvdmZzEmhh
     View Key  AViewKey1jf1aLTv7mu1zQ8FyNK4So6VrVoE5rk2xT7jywzS9Nptq
      Address  aleo13tny7lhjh7ckjm6ettxvzvdhj856dq6s657nef0p9h9gfruyavzqftkscg
```
Мы будем использовать **аккаунт S** для отправки и **аккаунт R** для получения.

В Aleo у каждого аккаунта есть несколько связанных ключей:

Их можно представить как пару ключей в асимметричной криптографической системе, где `Private key `- это закрытый ключ пары, а другой - открытый ключ, который вытекает из него. В этом понимании `Address` - это открытый ключ, который идентифицирует аккаунт, а `View Key` - открытый ключ, который позволяет расшифровать записи, принадлежащие адресу аккаунта (любому, кто его знает).

Пока хватит разговоров! Давайте запустим и развернем нашу программу.

## 4. Запуск нашей программы

Чтобы запустить нашу программу token, нам нужно сначала настроить файл _program.json_. Обновите private_key и адрес разработки на адрес только что созданного **аккаунта S**.

Он должен выглядеть следующим образом:

```javascript
{
    "program": "token.aleo",
    "version": "0.0.0",
    "description": "",
    "development": {
        "private_key": "APrivateKey1zkpAQpLeFgujVMkMEVKXhotR9XVa8B8nGfugMXYXHMdeHnN",
        "address": "aleo1nmjzszxsejh0ec6s9tgdx03g24l8e3ev0jy6fx2ckz7s4vt7hgxqu8hz04"
    },
    "license": "MIT"
}
```
Это важно, поскольку с точки зрения выполнения Aleo, **аккаунт S** будет тем, кто запускает программу для отправки токенов на **аккаунт R**. Это имеет некоторые последствия для безопасности, поскольку вы можете вводить записи только при запуске программы, принадлежащей аккаунту, указанному в _program.json_, как мы увидим через секунду.

Сначала нам нужно запустить функцию mint, чтобы сгенерировать начальное количество токенов, принадлежащих **S**. Эта функция требует ввода пароля для вывода записи с указанным количеством. Если заданный пароль неверен, выполнение завершится неудачей, что позволит избежать создания токенов.

Пароль для данного примера следующий:

```javascript
3634422524977942384127113436866104517282080062207687912678345956934082270693field
```
Нам нужно выполнить следующую команду:

```javascript
aleo run mint_token aleo1nmjzszxsejh0ec6s9tgdx03g24l8e3ev0jy6fx2ckz7s4vt7hgxqu8hz04 100u64 3634422524977942384127113436866104517282080062207687912678345956934082270693field 
```
и мы получаем следующую запись токена:

```javascript
 • Loaded universal setup (in 1472 ms)
🚀 Executing 'token.aleo/mint_token'...

 • Executing 'token.aleo/mint_token'...
 • Executed 'mint_token' (in 2174 ms)

➡️  Output

 • {
  owner: aleo1nmjzszxsejh0ec6s9tgdx03g24l8e3ev0jy6fx2ckz7s4vt7hgxqu8hz04.private,
  gates: 0u64.private,
  amount: 100u64.private,
  _nonce: 3024738992072387217402876176731225730589877991873828351104009809002984426287group.public
}

✅ Executed 'token.aleo/mint_token' (in "[...]/token")
```
Теперь давайте используем эту запись для передачи 10 токенов из **S** в **R**

```javascript
aleo run transfer_token "{
  owner: aleo1nmjzszxsejh0ec6s9tgdx03g24l8e3ev0jy6fx2ckz7s4vt7hgxqu8hz04.private,
  gates: 0u64.private,
  amount: 100u64.private,
  _nonce: 3024738992072387217402876176731225730589877991873828351104009809002984426287group.public
}" aleo13tny7lhjh7ckjm6ettxvzvdhj856dq6s657nef0p9h9gfruyavzqftkscg 10u64
```
и на выходе мы должны увидеть две записи, каждая из которых представляет текущее состояние наших записей токенов для каждого аккаунта.

```javascript
 • Loaded universal setup (in 1473 ms)
🚀 Executing 'token.aleo/transfer_token'...

 • Executing 'token.aleo/transfer_token'...
 • Executed 'transfer_token' (in 3620 ms)

➡️  Outputs

 • {
  owner: aleo1nmjzszxsejh0ec6s9tgdx03g24l8e3ev0jy6fx2ckz7s4vt7hgxqu8hz04.private,
  gates: 0u64.private,
  amount: 90u64.private,
  _nonce: 2178231086979351800436660566645386776768595203243256243508388701123108642520group.public
}
 • {
  owner: aleo13tny7lhjh7ckjm6ettxvzvdhj856dq6s657nef0p9h9gfruyavzqftkscg.private,
  gates: 0u64.private,
  amount: 10u64.private,
  _nonce: 4704084834675699921301424200265500298050115484153136728500446828605991979105group.public
}

✅ Executed 'token.aleo/transfer_token' (in "[...]/token")
```
Вот и все! Мы выполнили нашу первую передачу токенов.

В качестве тестового примера посмотрим, что произойдет, если мы поменяем местами два адреса (**S** и **R**) в последней команде `aleo run transfer_token`:

```javascript
aleo run transfer_token "{
  owner: aleo13tny7lhjh7ckjm6ettxvzvdhj856dq6s657nef0p9h9gfruyavzqftkscg.private,
  gates: 0u64.private,
  amount: 100u64.private,
  _nonce: 3024738992072387217402876176731225730589877991873828351104009809002984426287group.public
}" aleo1nmjzszxsejh0ec6s9tgdx03g24l8e3ev0jy6fx2ckz7s4vt7hgxqu8hz04 10u64
```
Мы получим следующий результат:

```javascript
 • Loaded universal setup (in 1461 ms)
⚠️  Input record for 'token.aleo' must belong to the signer
```
Это говорит нам о том, что владелец входной записи не принадлежит адресу отправителя, то есть адресу, который мы обновили в нашем _program.json_.

Как вы уже видите, программы Aleo выполняют несколько высокоуровневых проверок на уязвимости, что делает нашу программу достаточно отказоустойчивой по умолчанию.

## 5. Развертывание нашей программы на локальном уровне

Чтобы запустить Aleo Node локально, достаточно выполнить следующую команду внутри пути программы в другом терминале:

```javascript
aleo node start
```
Подождите пару секунд и обратите внимание на первые результаты:


```javascript
⏳ Starting a local development node for 'token.aleo' (in-memory)...

 • Loaded universal setup (in 1471 ms)
 • Executing 'credits.aleo/genesis'...
 • Executed 'genesis' (in 1872 ms)
 • Loaded universal setup (in 1423 ms)
 • Verified 'genesis' (in 46 ms)
 • Verified 'genesis' (in 46 ms)

🌐 Server is running at http://0.0.0.0:4180

📦 Deploying 'token.aleo' to the local development node...

 • Built 'mint_token' (in 11832 ms)
 • Certified 'mint_token': 264 ms
 • Built 'transfer_token' (in 23166 ms)
 • Certified 'transfer_token': 537 ms
 • Calling 'credits.aleo/fee'...
 • Executed 'fee' (in 2616 ms)
 • Verified certificate for 'mint_token': 89 ms
 • Verified certificate for 'transfer_token': 143 ms
 • Verified 'fee' (in 47 ms)
 • Verified certificate for 'mint_token': 89 ms
 • Verified certificate for 'transfer_token': 141 ms
 • Verified 'fee' (in 47 ms)
 • Verified certificate for 'mint_token': 88 ms
 • Verified certificate for 'transfer_token': 143 ms
 • Verified 'fee' (in 46 ms)

🛡️  Produced block 1 (ab1cz4e3zrw8xje7q6gutsjkqktvmwhq0yx3j4tqjeqnfr3c2j0f5gs5hwmf9)

{
  "previous_state_root": "1864323752948026853541213650623314215454919286649566834473029713121712183360field",
  "transactions_root": "2938300578986025380747616267226890561116633830917000361321232469947771414785field",
  "metadata": {
    "network": 3,
    "round": 1,
    "height": 1,
    "coinbase_target": 18446744073709551615,
    "proof_target": 18446744073709551615,
    "timestamp": 1660331897
  }
}

✅ Deployed 'token.aleo' in transaction 'at13pzudena0mk7xrj7m4tyar5x96ynr7m2q30c27lvc3gr7w5rn58q4agsk2'

 • Executing 'credits.aleo/transfer'...
 • Executed 'transfer' (in 3336 ms)
 • Verified 'transfer' (in 47 ms)
 • Verified 'transfer' (in 47 ms)

🛡️  Produced block 2 (ab1d2cypkhgv7fpardzd8pnn8mq8pwtwk453jyzc36cvt7z9r24vcpskj4tmd)

...
```
Как вы можете видеть здесь, у нас есть локальная нода, работающая и добывающая блоки, наша программа токенов уже развернута в транзакции, а сервер, работающий на http://localhost:4180, ждет запросов. Довольно удивительно, правда?

## Обзор наиболее важных конечных точек сервера

В этом разделе мы расскажем о наиболее полезных конечных точках HTTP RESTful, которые вы можете вызвать для получения информации из реестра вашей ноды. Вы можете использовать либо веб-браузер, либо команду `curl`.

> 💡 По умолчанию веб-служба ноды прослушивает соединение на порту 4180.

**Получение высоты последнего блока**

Чтобы получить последнюю высоту реестра вашей ноды, вы можете сделать `GET`-запрос к `http://localhost:4180/testnet3/latest/block/height`.

Ответ содержит значение последней высоты вашей работающей ноды.

**Получение хэша последнего блока**

Чтобы получить хэш последнего блока реестра вашей ноды, вы можете сделать `GET`-запрос по адресу

```javascript
http://localhost:4180/testnet3/latest/block/hash
```
Вы увидите ответ, содержащий хэш, подобный этому:

>_"ab14ja24wr9rdg2hmpym35kvw08ywwp6eyhknn23zr3ypwrxvqsjyzqpns7ml"_

**Получение последнего блока реестра**

Чтобы получить последний блок реестра вашей ноды, вы можете сделать `GET`-запрос по адресу

```javascript
http://localhost:4180/testnet3/latest/block
```
Вы увидите ответ в формате JSON, который содержит атрибуты блока.
Корневыми атрибутами являются: `block_hash`, `previous_hash`, `header`, `transactions` и `signature`.

**Получение блока по высоте**

Чтобы получить блок на заданной высоте из реестра вашей ноды, вы можете сделать `GET`-запрос по адресу

```javascript
http://localhost:4180/testnet3/block/{height}
```
Например:`http://localhost:4180/testnet3/block/8` вернет блок высотой 8.

**Получение записей, относящихся к аккаунту**

Вы можете получить записи тремя различными способами, в зависимости от того, какой тип записей вы хотите запросить. Для этого вам понадобится ваш ключ `ViewKey`. Существует два типа записей, потраченные и неизрасходованные, о них мы поговорим позже. Список связанных конечных точек вы можете увидеть ниже:

- `GET /testnet3/records/all`: Эта конечная точка извлекает все записи, принадлежащие заданному ключу `ViewKey`.

```javascript
curl --location --request GET 'localhost:4180/testnet3/records/all' -H 'Content-Type: application/json' -d '"AViewKey1iAf6a7fv6ELA4ECwAth1hDNUJJNNoWNThmREjpybqder"'
```

- `GET /testnet3/records/spent`: Эта конечная точка извлекает только потраченные записи, принадлежащие данному ключу `ViewKey`.

```javascript
curl --location --request GET 'localhost:4180/testnet3/records/spent' -H 'Content-Type: application/json' -d '"AViewKey1iAf6a7fv6ELA4ECwAth1hDNUJJNNoWNThmREjpybqder"'
```

- `GET /testnet3/records/all`: Эта конечная точка извлекает только неизрасходованные записи, принадлежащие данному ключу `ViewKey`.

```javascript
curl --location --request GET 'localhost:4180/testnet3/records/unspent' -H 'Content-Type: application/json' -d '"AViewKey1iAf6a7fv6ELA4ECwAth1hDNUJJNNoWNThmREjpybqder"'
```
В следующих постах мы начнем совершать и транслировать транзакции на наш локальный блокчейн разработки, добиваясь частного исполнения вне сети и частного хранения состояния на сети - ключевых особенностей экосистемы Aleo.