Инструкция по началу работы с Aleo
Tags: aleo, instructions, install, privacy
Published: 2022-08-22 14:52:00

Это руководство представляет собой описание некоторых простых примеров, которые помогут вам в работе с инструкциями Aleo.
Инструкции это как сборка для программ Aleo.
Программирование более высокого уровня может быть выполнено с помощью Leo, о котором вы можете прочитать [здесь](https://developer.aleo.org/developer/language/flying_tour/).

Прежде чем мы начнем, убедитесь, что у вас установлен и запущен Rust. Вы можете найти несколько примеров в [репозитории](https://github.com/AleoHQ/aleo/) проекта Aleo

##Установите Aleo


- Сборка из исходного кода

Вы можете установить `aleo`, собрав его из исходного кода следующим образом (мы рекомендуем устанавливать Aleo именно таким образом):

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

# Install Aleo
$ cargo install --path .
```
Сборка из [crates.io](https://crates.io/crates/aleo)

_(Эта опция устарела, мы рекомендуем собирать из исходников, чтобы использовать последнюю версию)_

Также вы можете установить сборник aleo из репозитория crates.io. В терминале запустите:

```javascript
cargo install aleo
```

На этом этапе вы можете запустить команду `aleo` в терминале:

```javascript
aleo
```

## Первые шаги

**Создание нового проекта Aleo**

Чтобы создать новый проект, мы воспользуемся командой `new`. Наш проект:

```javascript
aleo new foo
```
Это создаст папку **foo** и файлы с базовой структурой проекта:

- **README.md** скелет README с инструкциями по сборке
- **main.aleo** основной файл исходного кода.
- **program.json**, содержащий идентификационные данные проекта в формате JSON. В частности, адрес разработчика и его закрытый ключ для программы.

Давайте откроем _main.aleo_ и зададим функцию sum:

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

function sum:
    input r0 as u32.public;
    input r1 as u32.private;
    add r0 r1 into r2;
    output r2 as u32.private;
```

О том, что означает этот код, мы поговорим позже. Сначала мы построим нашу программу foo.

## Сборка проекта Aleo

Чтобы собрать проект, запустите его в главной папке:

```javascript
aleo build
```
В результате вы увидите следующее:

```javascript
⏳ Compiling 'foo.aleo'...

 • Loaded universal setup (in 1478 ms)
 • Built 'sum' (in 6323 ms)

✅ Built 'foo.aleo' (in "[...]/foo")
```
Сначала в вашу систему загружается "universal setup". Подробнее об этом можно прочитать [здесь](https://www.aleo.org/post/announcing-aleo-setup) или в [документе Marlin](https://eprint.iacr.org/2019/1047.pdf).

Как только universal setup будет готова, каждая функция в вашем файле _main.aleo_ собирается, создавая это в папке output:

- **sum.prover** проверяющая для функции sum.
- **sum.verifier** верификатор для функции sum.
- **main.avm** байткод вашей программы aleo для запуска виртуальной машиной.

Как вы уже догадались, у нас всего один .avm-файл для всей программы, но для каждой функции есть свой проверяющий и верификатор.

## Запуск программы

Вы можете запустить программу с помощью команды `aleo run`, за которой следует имя функции, которую вы хотите выполнить, и ее входные параметры. Давайте запустим наши функции sum:

```javascript
aleo run sum 2u32 3u32
```
когда выполнение будет завершено, вы должны увидеть следующий результат:

```javascript
🚀 Executing 'foo.aleo/sum'...

 • Calling 'foo.aleo/sum'...
 • Executed 'sum' (in 1170 ms)

➡️  Output

 • 5u32

✅ Executed 'foo.aleo/sum' (in "[...]/foo")
```

Как вы можете видеть здесь, выполнение функции sum длилось 1170 мс, а выходному регистру было присвоено значение `5u32`, представляющее sum входов.

## Обзор программы

Давайте рассмотрим программу foo внутри файла _main.aleo_:

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

function sum:
    input r0 as u32.public;
    input r1 as u32.private;
    add r0 r1 into r2;
    output r2 as u32.private;
```

Во-первых, нам нужно заявить программу следующим образом:

```javascript
program foo.aleo;
```

Затем мы можем начать писать её функции (или другие структуры Aleo, такие как интерфейсы, записи, закрытия, как мы увидим позже). В случае с функциями все очень просто:

```javascript
function [function_name]:
```
Функции состоят из трех основных частей:

- **Раздел input "ввода"**. Здесь мы определяем его входные параметры:

```javascript
    input r0 as u32.public;
    input r1 as u32.private;
```
Все в инструкциях Aleo заявляются/хранятся внутри регистра с типом (`i8`,`field`,`bool`, и т.д.) и параметром видимости (`public` или `private`). Регистры имеют имена `r0`, `r1`, ..., `rn`. Более подробно о регистрах, типах и видимости мы поговорим позже.

Итак, в данном случае мы используем `r0` и `r1` для хранения входов, передаваемых в последовательном порядке в программу, в виде значений `u32`, где мы можем хранить 32-битные беззнаковые целые числа для выполнения нашей функции sum.

- **Раздел instructions "инструкций"**. Следующий раздел, заключающий в себе ядро нашей функции. Здесь мы указываем количество инструкций Aleo, необходимых для того, чтобы наша программа сделала то, что мы хотим. Например, выполнение функции add:

```javascript
    add r0 r1 into r2;
```
За каждой инструкцией Aleo следуют ее входные параметры с заданными типами, а результат сохраняется в регистре _into_. Вы можете найти все доступные инструкции Aleo [здесь](https://hackmd.io/@aleo/SJ0mrYRv5#shr).

- **Раздел output "вывода"**. Подобно разделу ввода, раздел вывода делает то же самое для вывода программы. Это возвращаемое значение функции.

```javascript
 output r2 as u32.private;
```

## Разбираемся в некоторых концепциях

**Типы**

Aleo является типизированным языком. В настоящее время доступны следующие типы данных:

```javascript
Boolean
Field
Group
I8
I16
I32
I64
I128
U8
U16
U32
U64
U128
Scalar
```
Определены пользователем:

```javascript
Interface
Record
```
**Registers "Регистры"**

Регистр - это место, где вы храните данные, чтобы затем иметь возможность их изменять.

**Interfaces "Интерфейсы"**

Interfaces - это определяемые пользователем структуры данных. Они очень похожи на традиционные структуры в обычных языках программирования. Интерфейсы можно хранить в регистрах, как и любые другие типы данных Aleo.

Например, давайте создадим интерфейс, представляющий массив фиксированного размера из 3 элементов. Добавьте это в нижнюю часть файла _main.aleo_:

```javascript
interface array3:
    a0 as u32;
    a1 as u32;
    a2 as u32;
```
Теперь, для примера, давайте закодируем функцию, которая добавляет единицу к каждому элементу регистра с хранящимся в нем типом данных array3.

```javascript
function sum_one_to_array3:
    input r0 as array3.private;
    add r0.a0 1u32 into r1;
    add r0.a1 1u32 into r2;
    add r0.a2 1u32 into r3;
    cast r1 r2 r3 into r4 as array3;
    output r4 as array3.private;
```

Как видите, мы можем ввести интерфейс в регистр `r0` и получить доступ к элементам интерфейса с помощью синтаксиса `.` Мы выполняем инструкцию `add` над каждым элементом, сохраняя результаты в регистрах `r1`, `r2` и `r3`, и, наконец, используем команду cast для создания нового интерфейса array3 в `r4`.

Теперь давайте запустим его. В этом случае единственное, что вам нужно знать, это то, что интерфейсы передаются в cli в следующем формате:

```javascript
"{a0: 1u32, a1: 2u32, a2: 3u32}"
```
Теперь мы можем выполнить команду `aleo run`. Мы очистим проект, чтобы подхватить новый код:

```javascript
aleo clean && aleo run sum_one_to_array3 "{a0: 0u32, a1: 1u32, a2: 2u32}"
```

И на выходе мы получаем новый элемент набора array3:


```javascript
🚀 Executing 'foo.aleo/sum_one_to_array3'...

 • Calling 'foo.aleo/sum_one_to_array3'...
 • Executed 'sum_one_to_array3' (in 1331 ms)

➡️  Output

 • {
  a0: 1u32,
  a1: 2u32,
  a2: 3u32
}

✅ Executed 'foo.aleo/sum_one_to_array3' (in "[...]/foo")
```

**Records "Записи"**

Record - это фундаментальная структура данных для кодирования пользовательских активов и состояния приложения. Они очень похожи на интерфейсы, но у них есть два необязательных параметра:

```javascript
record token:
    owner as address.private
    gates as u64.private
```
`owner` означает адрес Aleo, которому принадлежит запись, а `gates` - количество кредитов, которые запись должна потратить.

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

При выполнении функции Aleo в качестве входных регистров можно передавать только регистры, принадлежащие адресу приложения. В противном случае возникнет ошибка, и приложение не будет запущено.

Адрес приложения для разработки можно найти в файле _program.json_:

```javascript
{
    "program": "foo.aleo",
    "version": "0.0.0",
    "description": "",
    "development": {
        "private_key": "APrivateKey1zkpFsQNXJwdvjKs9bRsM91KcwJW1gW4CDtF3FJbgVBAvPds",
        "address": "aleo1x5nz5u4j50w482t5xtqc3jdwly9s8saaxlgjz0wvmuzmxv2l5q9qmypx09"
    },
    "license": "MIT"
}
```

**Состояние Aleo в двух словах**

В Aleo состояние приложения управляется с помощью записей. Учетная запись Aleo может создать транзакцию для потребления записи и создания новой записи на ее месте. Записи в Aleo шифруются по адресу владельца записи, что обеспечивает полную конфиденциальность всех записей в Aleo.

## Ваша первая программа Aleo: Выполнение перевода

Рассмотрим эту программу:

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

record token:
    owner as address.private;
    gates as u64.private;
    amount as u64.private;

function transfer_amount:
    //  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 of sender
    sub r0.amount r2 into r3;
    // final balance of 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;
```
Во-первых, мы определили наш собственный тип данных записи под названием `token`, который имеет два необязательных параметра, `owner` и `gates`, и определяемый пользователем параметр под названием `amount`, представляющий количество имеющихся у нас токенов.

Функция `transfer_amount` получает 3 входных параметра (запись `sender`, запись `receiver` и `amount`) и сохраняет их в 3 регистрах (`r0`, `r1` и `r2`). После этого она вычисляет окончательный баланс для обоих регистров и сохраняет его в `r3` и `r4` (используя инструкции `sub` и `add` для вычисления вычитания и сложения). С этими итоговыми суммами он создает выходные записи для отправителя и получателя, сохраняя их в `r5` и `r6`. Наконец, обе записи отправляются из функции с помощью инструкции **output**.

Для запуска этой функции первым параметром является входная запись программы. Формат этого параметра такой же, как и для интерфейсных типов:

```javascript
{
  owner: aleo1x5nz5u4j50w482t5xtqc3jdwly9s8saaxlgjz0wvmuzmxv2l5q9qmypx09.private,
  gates: 0u64.private,
  amount: 50u64.private
}
```
где:

- owner: публичный адрес программы, как указано в `development.address` файла build/program.json.
- gates: параметры, которые есть у записи.
- другие параметры: зависят от самой программы (в данном примере мы использовали параметр _amount_ со значением 50).

Запустим функцию `transfer_amount` (если вы следуете за нами, не забудьте использовать адрес, найденный в program.json для поля owner):

```javascript
aleo clean && aleo run transfer_amount "{
owner: aleo1x5nz5u4j50w482t5xtqc3jdwly9s8saaxlgjz0wvmuzmxv2l5q9qmypx09.private,
gates: 0u64.private,
amount: 50u64.private
}" aleo1h3gu7fky36y8r7v2x9phc434fgf20g8qd7c7u45v269jfw6vmugqjegcvp 10u64
```
Мы получаем следующие результаты:

```javascript
🚀 Executing 'foo.aleo/transfer_amount'...

 • Calling 'foo.aleo/transfer_amount'...
 • Executed 'transfer_amount' (in 3520 ms)

➡️  Outputs

 • {
  owner: aleo1x5nz5u4j50w482t5xtqc3jdwly9s8saaxlgjz0wvmuzmxv2l5q9qmypx09.private,
  gates: 0u64.private,
  amount: 40u64.private
  _nonce: 2293253577170800572742339369209137467208538700597121244293392265726446806023group.public
}
 • {
  owner: aleo1h3gu7fky36y8r7v2x9phc434fgf20g8qd7c7u45v269jfw6vmugqjegcvp.private,
  gates: 0u64.private,
  amount: 10u64.private
  _nonce: 2323253577170856894742339369235137467208538700597121244293392765726742543235group.public
}

✅ Executed 'foo.aleo/transfer_amount' (in "[...]/foo")
```

Вот и все. Вы передали свои первые собственные определенные токены в Aleo!

Примечание: _nonce не записывается в инструкции Aleo. Сборка выводит _nonce в выводах записей. Пользователь должен указать его в качестве ввода при использовании записи.

Итоговые замечания

Программы Aleo могут создавать и исполнять _криптографические схемы_, написанные в инструкциях Aleo. Это вводит некоторые ограничения, которых нет в обычных языках программирования. Например, при использовании _тернарного_ оператора для наличия ответвления в потоке программы необходимо заранее иметь оба результата (т.е. результат каждого ответвления должен быть вычислен и известен до выполнения тернарного оператора). Логическое сравнение должно быть между регистрами, а не между возвратными значениями вызываемых функций.

**Источник** - https://www.entropy1729.com/getting-started-aleo-instructions/

Перевел - egormajj#0340