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

Инструкции Aleo и SnarkVM

Добро пожаловать в руководство по эксплуатации Aleo. Инструкции Aleo — это промежуточное представление программ Aleo. Все программы Leo компилируются в инструкции Aleo, которые компилируются в байт-код. Мы рекомендуем изучать и использовать инструкции Aleo, если вашей целью является детальное проектирование схем или если вы реализуете компилятор, который читает на языке высокого уровня, отличном от Leo, и хотите, чтобы ваши программы работали на Aleo.

Программы Aleo представляют собой файлы с расширением .aleo. Программы Aleo содержат инструкции Aleo — язык программирования, подобный ассемблеру. Инструкции Aleo компилируются в коды операций AVM, которые могут выполняться виртуальной машиной Aleo.

Установите SnarkVM для компиляции и выполнения инструкций Aleo.

ИНФОРМАЦИЯ

SnarkVM в настоящее время находится в активной разработке. Пожалуйста, следите за репозиторием на GitHub на предмет возможных критических изменений.

Установка SnarkVM

Перейдите к разделу Установка для получения информации о том, как установить SnarkVM.

Привет Алео Инструкции

Разработайте свою первую программу инструкций Aleo Hello Aleo.

Алео Инструкция

Изучите основные понятия и синтаксис инструкций Aleo.

Прочтите полный список поддерживаемых кодов операций AVM.

Формальная языковая документация

Проверьте реализацию вашей программы или компилятора на соответствие грамматике инструкций Aleo.

Изучите формальную спецификацию грамматики ABNF для получения полного формального синтаксиса инструкций Aleo.

Документация по интерфейсу командной строки

Интерфейс командной строки SnarkVM предоставляет набор команд, упрощающих программирование с помощью инструкций Aleo.

Дополнительный материал

Установите Aleo по инструкции для вашего любимого редактора кода.

Монтаж

1. Установите необходимые условия

1.1 Установите Git:

bit.ly/start-git

1.2 Установите Rust:

bit.ly/start-rust

1.3 Проверьте предварительные условия

git --version
cargo --version

2. Создайте исходный код

Вы можете установить SnarkVM, собрав исходный код следующим образом:

# Download the source code
git clone https://github.com/AleoHQ/snarkVM
cd snarkvm
# Build in release mode
$ cargo install --path 

Это создаст исполняемый файл ~/.cargo/bin/snarkvm.

Теперь, чтобы использовать CLI SnarkVM, в вашем терминале запустите:

snarkvm

Привет Алео Инструкция

1. Создайте и постройте новый проект

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

snarkvm new foo

Это создаст каталог foo и файлы с базовой структурой проекта:

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

Файл main.aleo должен иметь следующее содержимое:

// The 'foo.aleo' program.
program foo.aleo;
function hello:
    input r0 as u32.public;
    input r1 as u32.private;
    add r0 r1 into r2;
    output r2 as u32.private;

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

snarkvm run hello 2u32 3u32

Вы увидите такой вывод:

• Loaded universal setup (in 1478 ms)
⛓  Constraints
 •  'foo.aleo/hello' - 35 constraints (called 1 time)
➡️  Output
 • 5u32
✅ Finished 'foo.aleo/hello' (in "/Users/collin/code/snarkVM/foo")

Как видите, выходные данные имеют значение 5u32, представляющее сумму входных данных.

2. Выполнение программы

Вы можете выполнить программу с помощью команды snarkvm execute, за которой следует имя функции, которую вы хотите выполнить, и ее входные параметры:

snarkvm execute hello 2u32 3u32

Когда выполнение завершится, вы должны увидеть следующий вывод:

• Loaded universal setup (in 1478 ms)
⛓  Constraints
 •  'foo.aleo/hello' - 35 constraints (called 1 time)
➡️  Output
 • 5u32
 
  {"type":"execute","id":"at1 ... (transaction object truncated for brevity)
✅ Executed 'foo.aleo/hello' (in "/Users/collin/code/snarkVM/foo")

Как видите, выходные данные имеют значение 5u32, представляющее сумму входных данных.

В вашу среду загружается универсальная установка. Подробнее об этом можно прочитать в Записке Марлина.

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

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

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

3. Обзор программы

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

// The 'foo.aleo' program.
program foo.aleo;
function hello:
    input r0 as u32.public;
    input r1 as u32.private;
    add r0 r1 into r2;
    output r2 as u32.private;

Сначала нам нужно объявить программу следующим образом:

program foo.aleo;

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

В случае с функциями все очень просто:

function [function_name]:

Функции состоят из трех основных частей:

  • Раздел ввода

Здесь мы объявляем его входные параметры:

input r0 as u32.public;
input r1 as u32.private;

Все в инструкциях Aleo объявляется/хранится внутри регистра с типом (i8,field,bool и т. д.) и опцией видимости (public или private), регистры называются r0, r1, ..., rn.

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

  • Раздел инструкций

Следующий раздел содержит ядро ​​нашей функции: здесь мы вызываем инструкции Aleo, которые нам нужны, чтобы наша программа делала то, что мы хотим. Например, выполнив операцию сложения:

add r0 r1 into r2;

За каждой инструкцией aleo следуют ее входные параметры с определенными типами, а результат сохраняется в регистре, указанном после into.

Вы можете найти все доступные коды операций инструкций Aleo здесь.

  • Раздел вывода

Подобно разделу ввода, раздел вывода делает то же самое для вывода программы. Это возврат функции.

output r2 as u32.private;

4. Типы

Aleo использует строго типизированный синтаксис. Язык поддерживает 16 примитивных типов и позволяет пользователям определять собственные типы.

Примитивные типы Aleo включают:

address
boolean
field
group
i8
i16
i32
i64
i128
u8
u16
u32
u64
u128
scalar

Пользователи могут определять собственные типы, используя ключевые слова struct или record. Мы рассмотрим их в следующих нескольких разделах.

4.1 Регистры

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

4.2 Структуры

Структуры — это определяемые пользователем структуры данных. Они очень похожи на традиционные структуры обычных языков программирования. Вы можете хранить структуры в регистрах, как и любые другие типы данных Aleo.

Например, давайте создадим структуру, представляющую массив фиксированного размера из трех элементов. Добавьте это в конец файла main.aleo:

struct array3:
    a0 as u32;
    a1 as u32;
    a2 as u32;

Теперь, просто в качестве примера, давайте напишем функцию, которая добавляет единицу к каждому элементу регистра с хранящимся в нем типом данных array3.

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 и, наконец, используем команду приведения для создания новой структуры array3 в r4.

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

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

Теперь мы можем выполнить команду aleo run. Очистим проект, чтобы подобрать новый код:

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

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

➡️  Output
 • {
  a0: 1u32,
  a1: 2u32,
  a2: 3u32
}
✅ Executed 'foo.aleo/sum_one_to_array3' (in "[...]/foo")

4.3 Записи

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

record token:
    owner as address.private
    microcredits as u64.private

owner относится к адресу Aleo, которому принадлежит запись, а microcredits — это сумма кредитов, которую запись должна потратить.

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

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

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

{
    NETWORK=testnet3
    PRIVATE_KEY=APrivateKey1zkpFsQNXJwdvjKs9bRsM91KcwJW1gW4CDtF3FJbgVBAvPds
}

4.4 Состояние Алео

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

5. Ваша первая программа Алео: Оформление перевода

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

// The 'foo.aleo' program.
program foo.aleo;
record token:
    owner as address.private;
    microcredits 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.microcredits 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, необязательный параметр microcredits и определяемый пользователем параметр amount, представляющий количество имеющихся у нас токенов.

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

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

{
  owner: aleo1x5nz5u4j50w482t5xtqc3jdwly9s8saaxlgjz0wvmuzmxv2l5q9qmypx09.private,
  microcredits: 0u64.private,
  amount: 50u64.private
}

Где:

  • владелец: публичный адрес программы, указанный в PRIVATE_KEY файла .env.
  • микрокредиты: сумма кредитов, которыми владеет запись.
  • остальные параметры: в зависимости от самой программы (в данном примере мы использовали параметр amount со значением 50).

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

aleo clean && aleo run transfer_amount "{
owner: aleo1x5nz5u4j50w482t5xtqc3jdwly9s8saaxlgjz0wvmuzmxv2l5q9qmypx09.private,
microcredits: 0u64.private,
amount: 50u64.private
}" aleo1h3gu7fky36y8r7v2x9phc434fgf20g8qd7c7u45v269jfw6vmugqjegcvp 10u64

Мы получаем следующие выходные записи:

🚀 Executing 'foo.aleo/transfer_amount'...
 • Calling 'foo.aleo/transfer_amount'...
 • Executed 'transfer_amount' (in 3520 ms)
➡️  Outputs
 • {
  owner: aleo1x5nz5u4j50w482t5xtqc3jdwly9s8saaxlgjz0wvmuzmxv2l5q9qmypx09.private,
  microcredits: 0u64.private,
  amount: 40u64.private
  _nonce: 2293253577170800572742339369209137467208538700597121244293392265726446806023group.public
}
 • {
  owner: aleo1h3gu7fky36y8r7v2x9phc434fgf20g8qd7c7u45v269jfw6vmugqjegcvp.private,
  microcredits: 0u64.private,
  amount: 10u64.private
  _nonce: 2323253577170856894742339369235137467208538700597121244293392765726742543235group.public
}
✅ Executed 'foo.aleo/transfer_amount' (in "[...]/foo")

Вот и все. Вы перенесли свои первые токены, определенные владельцем, в Aleo!

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

Спасибо, что дочитали эту статью до конца, и подпишитесь на уведомления.

Ниже приведены все официальные ссылки на Aleo:

Сайт — https://www.aleo.org/
Discord — https://discord.gg/aleohq
Twitter — https://twitter.com/AleoHQ
GitHub — https://github.com/AleoHQ