Полная интерпретация улучшенной грамматики Starknet

Оригинал: Улучшенный синтаксис Starknet

Перевод и корректура: "Китайское сообщество Starknet"

Полная интерпретация улучшенной грамматики Старкнета

обзор

Версия 2 компилятора Cairo вносит изменения в синтаксис Starknet, чтобы сделать код более явным и безопасным. Публичный интерфейс смарт-контракта определяется с помощью трейтов, а доступ к хранилищу осуществляется с помощью трейта ContractState. Закрытые методы должны быть определены с реализацией, отличной от общедоступного интерфейса. События теперь определяются как перечисления, где каждый вариант является структурой с тем же именем.

Отказ от ответственности: термины, используемые здесь, относятся к различным версиям компилятора Cairo, а синтаксис является предварительным, поскольку сообщество Starknet все еще обсуждает, какой термин лучше использовать. После определения эта статья будет соответствующим образом обновлена.

Компилятор v2

Буквально на прошлой неделе на Github была выпущена новая основная версия 2.0.0-rc0 компилятора Cairo. Новый компилятор вносит значительные улучшения в подключаемый модуль Starknet, делая наш код более безопасным, явным и пригодным для повторного использования. Обратите внимание, что эта новая версия компилятора еще не поддерживается в тестовой или основной сети Starknet, поскольку над ней все еще работают в интегрированной среде.

Цель этой статьи — показать вам, как переписать смарт-контракт Starknet, созданный для компилятора Cairo версии 1.x, в смарт-контракт, совместимый с компилятором версии 2.x. Нашей отправной точкой является смарт-контракт Ownable, созданный в предыдущей статье, который совместим с компилятором Cario версии 1.x.

[contract] mod Ownable {использовать starknet::ContractAddress;использовать starknet::get_caller_address;

[event] fn OwnershipTransferred(предыдущий_владелец: ContractAddress, новый_owner: ContractAddress) {}

struct Storage {владелец: ContractAddress,}

[constructor] fn конструктор() {пусть deployer = get_caller_address();owner::write(deployer);}

[view] fn get_owner() -> ContractAddress {owner::read()}

[external] fn transfer_ownership(новый_owner: ContractAddress) {only_owner(); пусть предыдущий_owner = owner::read();owner::write(new_owner);OwnershipTransferred(предыдущий_owner, новый_owner) ;}

fn only_owner() {let caller = get_caller_address();assert(caller == owner::read(), 'Вызывающий абонент не является владельцем');

Настройки проекта

Поскольку Protostar еще не поддерживает компилятор v2, в этой статье будет использоваться предварительный выпуск Scarb (версия 0.5.0-alpha.1), который его поддерживает. Чтобы установить эту конкретную версию Scarb, вы можете использовать следующую команду.

$ --proto '=https' --tlsv1.2 -sSf | bash -s -- -v 0.5.0-альфа.1

После завершения установки убедитесь, что у вас правильная версия.

$ scarb --version>>>scarb 0.5.0-alpha.1 (546dad33d 2023-06-19)cairo:2.0.0-rc3()

Теперь можно создать проект Scarb.

$ scarb новый cairo1_v2$cdcairo1_v2

Вы должны получить структуру папок, как показано ниже.

$ tree .>>>.├── Scarb.toml└── src└──lib.cairo

Чтобы Scarb мог скомпилировать смарт-контракты Starknet, плагин Starknet должен быть включен в качестве зависимости.

// Скарб.томл... [dependencies] Старкнет = "2.0.0-rc3"

После завершения настройки мы можем перейти к src/lib.cairo и начать писать смарт-контракты.

Хранилище и конструктор

Во второй версии компилятора Cairo смарт-контракты по-прежнему определяются модулями, аннотированными атрибутом контракта, только на этот раз атрибут назван в честь плагина, который его определяет, в данном случае starknet.

#[starknet::contract]мод Владелец {}

Внутреннее хранилище по-прежнему определяется как структура, которая должна называться Storage, только на этот раз она должна быть аннотирована атрибутом хранилища.

#[starknet::contract]mod Ownable {use super::ContractAddress; # [storage] struct Storage {владелец: ContractAddress,

Чтобы определить конструктор, мы аннотируем функцию атрибутом конструктора, как мы это делали в v1, преимущество в том, что теперь функция может иметь любое имя, ее не нужно называть «конструктором», как в v1. Хотя это и не обязательно, я по-прежнему буду называть функцию «конструктором» вне соглашения, но вы можете называть ее по-другому.

Другое важное изменение заключается в том, что теперь конструктор автоматически передает ссылку на ContractState, который действует как посредник для хранения переменных, в данном случае «владельца».

#[starknet::contract]mod Ownable {use super::ContractAddress; # [storage] struct Storage {владелец: ContractAddress,} # [constructor] конструктор fn (ref self: ContractState) {let deployer = get_caller_address();self.owner.write(deployer);

Обратите внимание, что синтаксис записи и чтения хранилища изменился по сравнению с v1. Прежде чем мы сделали owner::write(), теперь мы делаем self.owner.write(). То же самое относится и к чтению из хранилища.

Кстати, тип ContractState не нужно вносить в область видимости вручную, он включен в прелюдию.

Общедоступные методы

Важным отличием от версии 1 компилятора Cairo является то, что теперь нам нужно явно определить публичный интерфейс смарт-контракта, используя трейты, аннотированные атрибутом starknet::interface.

используйте starknet::ContractAddress;

#[starknet::interface]trait OwnableTrait { fn transfer_ownership(ref self: T, new_owner: ContractAddress); fn get_owner(self: @T) -> ContractAddress;}

#[starknet::contract]mod Ownable { ...}

Если вы помните исходный код из v1, наш смарт-контракт имеет два «публичных» метода (get_owner и transfer_ownership) и один «частный» метод (only_owner). Эта функция имеет дело только с общедоступными методами и не полагается на атрибуты «внешний» или «представление», чтобы указать, какие методы могут изменять состояние контракта, а какие нет. Вместо этого теперь это делается явным по типу параметра self.

Если метод требует ссылки на ContractStorage (что после реализации делает универсальный T), этот метод может изменить внутреннее состояние смарт-контракта. Это то, что мы привыкли называть «внешним» методом. С другой стороны, если методу требуется снимок ContractStorage, он может только прочитать его, но не изменить. Это то, что мы привыкли называть методом «просмотр».

Теперь мы можем создать реализацию черты, которую мы только что определили, используя ключевое слово impl. Помните, Cairo отличается от Rust тем, что реализации имеют имена.

используйте starknet::ContractAddress;

#[starknet::interface]trait OwnableTrait { fn transfer_ownership(ref self: T, new_owner: ContractAddress); fn get_owner(self: @T) -> ContractAddress;}

#[starknet::contract]mod Ownable { ... #[external(v0)] impl OwnableImpl of super::OwnableTrait { fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { let prev_owner = self.owner.read(); self.owner.write(новый_владелец); }

fn get_owner(self: @ContractState) -> ContractAddress { self.owner.read() }

Мы создаем реализацию нашего трейта внутри модуля, определяющего смарт-контракт, передавая тип ContractState как общий тип T, чтобы к хранилищу можно было получить доступ как к конструктору.

Наша реализация помечена атрибутом external(v0). Версия 0 в атрибуте означает, что селектор происходит только от имени метода, как это было в прошлом. Недостатком является то, что если вы определите другую реализацию другого трейта для своего смарт-контракта, а два трейта используют одно и то же имя для одного из своих методов, компилятор выдаст ошибку из-за повторяющегося селектора.

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

Частные методы

Нам также нужно определить другой метод для смарт-контракта, only_owner. Этот метод проверяет, должен ли вызывающий его человек быть владельцем смарт-контракта.

Поскольку это частный метод, который нельзя вызывать извне, его нельзя определить как часть OwnableTrait (общедоступный интерфейс смарт-контракта). Вместо этого мы будем использовать атрибут generate_trait для создания новой реализации автоматически сгенерированного типажа.

...#[starknet::contract]mod Ownable { ... #[generate_trait] impl PrivateMethods of PrivateMethodsTrait { fn only_owner(self: @ContractState) { let caller = get_caller_address(); assert(вызывающий == self.owner.read(), 'Вызывающий не является владельцем'); }

Теперь можно использовать метод only_owner, вызвав self.only_owner() там, где это необходимо.

#[starknet::contract]mod Ownable { ... #[external(v0)] impl OwnableImpl of super::OwnableTrait { fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { self.only_owner (); ... } ... }

#[generate_trait] impl PrivateMethods of PrivateMethodsTrait { fn only_owner(self: @ContractState) { ... }

событие

В Cairo v1 событие было просто функцией без тела и аннотировано атрибутом события, в то время как в v2 событие представляет собой перечисление, аннотированное тем же атрибутом, но теперь реализованное с использованием некоторых дополнительных функций.

...#[starknet::contract]mod Ownable { ... # [event] #[derive(Drop, starknet::Event)] enum Event { OwnershipTransferred: OwnershipTransferred, }

#[derive(Drop, starknet::Event)] struct OwnershipTransferred { # [key] предыдущий_владелец: ContractAddress, # [key] новый_владелец: адрес контракта,

Каждый вариант перечисления событий должен быть структурой с тем же именем. В этой структуре мы используем необязательный атрибут ключа, чтобы определить все значения, которые мы хотим выдать, чтобы сообщить системе, какие значения мы хотим, чтобы Starknet индексировал, чтобы индексатор мог быстрее искать и извлекать. В данном случае мы хотим проиндексировать два значения (prev_owner и new_owner).

Черта ContractState определяет метод отправки, который можно использовать для отправки событий.

...#[starknet::contract]mod Ownable { ... #[external(v0)] impl OwnableImpl of super::OwnableTrait { fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { .. .self.emit(Event::OwnershipTransferred(OwnershipTransferred { предыдущий_владелец: предыдущий_владелец, новый_владелец: новый_владелец, })); } ... } ...}

С помощью этой последней функции мы завершили миграцию смарт-контракта Ownable с версии 1 на версию 2. Полный код показан ниже.

используйте starknet::ContractAddress;

#[starknet::interface]trait OwnableTrait { fn transfer_ownership(ref self: T, new_owner: ContractAddress); fn get_owner(self: @T) -> ContractAddress;}

#[starknet::contract]mod Ownable { use super::ContractAddress; используйте starknet::get_caller_address;

[event] #[derive(Drop, starknet::Event)] enum Event { OwnershipTransferred: OwnershipTransferred, }

#[derive(Drop, starknet::Event)] struct OwnershipTransferred { # [key] предыдущий_владелец: ContractAddress, # [key] новый_владелец: адрес контракта, }

[storage] struct Storage { владелец: ContractAddress, }

[constructor] конструктор fn (ref self: ContractState) { let deployer = get_caller_address(); self.owner.write(развертыватель); }

#[external(v0)] impl OwnableImpl of super::OwnableTrait { fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) { self.only_owner(); пусть prev_owner = self.owner.read(); self.owner.write(новый_владелец); self.emit(Event::OwnershipTransferred(OwnershipTransferred {предыдущий_владелец: предыдущий_владелец, новый_владелец: новый_владелец, })); }

fn get_owner(self: @ContractState) -> ContractAddress { self.owner.read() } }

#[generate_trait] impl PrivateMethods of PrivateMethodsTrait { fn only_owner(self: @ContractState) { let caller = get_caller_address(); assert(вызывающий == self.owner.read(), 'Вызывающий не является владельцем'); }

Вы также можете найти этот код на Github.

в заключение

Версия 2 компилятора Cairo привносит в Starknet новый синтаксис, который делает код смарт-контракта более совместимым с самим Cairo и, соответственно, более похожим на Rust. Даже за счет более громоздкого кода преимущества безопасности стоят компромисса.

В этой статье мы не коснулись всего, что касается нового синтаксиса, особенно того, как он взаимодействует с другими смарт-контрактами, но вы можете прочитать журнал изменений компилятора, прочитать этот пост на форуме или посмотреть видео на канале StarkWare на YouTube, чтобы узнать больше. об этом, чтобы узнать больше информации.

Эта новая версия компилятора будет доступна в тестовой сети Starknet через несколько недель и в основной сети через несколько недель, поэтому пока не пытайтесь развернуть этот код, он пока не будет работать.

Каир становится только лучше.

ресурс

  • Синтаксис контракта — руководство по миграции
  • Cairo 1: синтаксис контракта развивается
Посмотреть Оригинал
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
  • Награда
  • комментарий
  • Поделиться
комментарий
0/400
Нет комментариев
  • Закрепить