Автор этой статьи:MoveMoon[1]
добро пожаловать в Переместить учебник! В этом уроке мы разработаем Move Некоторые шаги кода включают в себя Move Проектирование, внедрение, модульное тестирование и формальная верификация модулей.
Всего существует девять шагов:
BasicCoin
модульBaseCoin
модульBasicCoin
модуль Добавитьи Используйте модульные тестыBasicCoin
модуль СтандартизацияBasicCoin
модуль Напишите формальную спецификациюкаждыйшагшаг Всеодеялодизайнстановитьсясуществоватьсоответствующийизstep_x
автономный в папке。Например,Если вы хотите пропустить Нет. 1 к Нет. 4 шагизсодержание,Пожалуйста, не стесняйтесь прыгатьк Нет. 5 шаг,потому чтодляяихсуществовать Нет. 5 шаг Изнаписано раньшеизвсекод Всесуществоватьstep_5
в папке。существовать Некоторыйшагшагизконец,яих还Сумкавключить больше Расширенные темыиз Дополнительный материал.
Код учебника: https://github.com/move-language/move/tree/main/language/documentation/tutorial.
Давайте начнем прямо сейчас!
Если вы еще этого не сделали, откройте терминал и клонируйте Move. repository[2]。
git clone https://github.com/move-language/move.git
Входитьmove
каталог и запуститеdev_setup.sh
Скрипт。
cd move
./scripts/dev_setup.sh -ypt
Следуйте инструкциям сценария, чтобы установить все зависимости Move.
Должен Скрипт Определить переменные средыдобавить вприезжатьтыиз~/.profile
в файле。Включите его, выполнив эту командусуществовать Внутри。
source ~/.profile
Затем установите инструменты командной строки Move, выполнив следующую команду.
cargo install --path language/tools/move-cli
Вы можете проверить, работает ли это, выполнив следующую команду.
move --help
Вы должны увидеть что-то вроде этого, а также список и описание некоторых команд.
move-package
Execute a package command. Executed in the current directory or the closest containing Move package
USAGE:
move [OPTIONS] <SUBCOMMAND>
OPTIONS:
--abi Generate ABIs for packages
...
еслитыдуматьпопытаться найтиприезжать Какие команды доступныизи ониизэффект,Беги с--help
логотипиз Команда или подкоманда распечатает документ.。
существовать, прежде чем переходить к следующим шагам,cd
приезжать Учебное пособие Оглавление。
cd <path_to_move>/language/documentation/tutorial
Поддержка перемещения кода Visual Studio
Visual Studio Code имеет официальную поддержку Move. Сначала вам необходимо установить анализатор Move:
cargo install --path language/move-analyzer
Теперь вы можете открыть VS Код, поиск в панели расширений move-analyzer
установить VS Расширять,и установить его。Подробнееиз Объясните, что это нормальносуществовать РасширятьизREADME[3] найден в
Изменять Оглавление Входить`step_1/BasicCoin`[4]Оглавление。тыотвечать Долженсмотретьприезжатьодинназывается sources
из Оглавление -- Это все, что есть в этом пакете Move код Местосуществоватьизместо。ты还отвечать ДолженсмотретьприезжатьодинMove.toml
документ。еслитыпривычный Rust и Cargo,Move.toml
документиCargo.toml
документсходство,sources
Оглавлениеиsrc
Оглавлениесходство。
Давайте посмотрим на некоторые Move код! существоватьтывыбиратьиз Открыть в редакторе`sources/FirstModule.move`[5]。тывстречасмотретьприезжатьизсодержание Сразудаэтот:
// sources/FirstModule.move
module 0xCAFE::BasicCoin {
...
}
Это определяет Moveмодуль[6]。модульда Move Компонент кода, который определяется как конкретный адрес: Модуль можно опубликовать по адресу. существуют В этом примере,BasicCoin
модульможет толькосуществовать0xCAFE
Опубликовать под。
Примечание переводчика: Модули публикуются под адресом издателя. Стандартная библиотека выпущена по адресу 0x1.
Сейчас существует, давайте посмотрим на этот файл из следующей части,яихопределениеодин Структура[7]выражатьодинс данным Value
из Coin
。
module 0xCAFE::BasicCoin {
struct Coin has key {
value: u64,
}
...
}
Просматривая остальную часть файла, мы видим определение функции, которая создает Coin
Структураихрани этосуществоватьодинна счету:
module 0xCAFE::BasicCoin {
struct Coin has key {
value: u64,
}
public fun mint(account: signer, value: u64) {
move_to(&account, Coin { value })
}
}
Давайте посмотрим на эту функцию и ее содержимое:
value
Приходите чеканить монеты。Coin
,и использоватьmove_to
оператор сохраняет этосуществоватьaccount
Вниз。Давайте убедимся, что его можно построить! Это можно сделать черезсуществоватьпрограммное обеспечение Сумкав папке(`step_1/BasicCoin`[9])Вниз,использоватьbuild
команда для завершения。
move build
Расширенные концепции
move new <pkg_name>
Move.toml
документиз Более подробная информация доступнасуществоватьMove книгаизчасть упаковки[11]найден в。NamedAddr
значение для компиляциимодуль,таким образом получитьприезжатьдругойизбайт-код,Вы можете выполнить развертывание на основе адреса, который вы контролируете. Если часто использовать,МожетсуществоватьMove.toml
в файлеиз[address]
частично определить,Например: [addresses]
SomeNamedAddress = "0xC0FFEE"
copy
:разрешено иметь этоспособностьизтипиззначениекопировать。drop
:разрешено иметь этоспособностьизтипиззначениевыбросить(разрушать)。store
:разрешено иметь этоспособностьизтипиз Стоит сэкономитьсуществоватьв глобальном хранилищеиз Структурасередина。key
: Этому типу разрешено выполнять глобальные операции хранения и ключи.Поэтому в BasicCoin
модульсередина,яих说 Coin
Структура Можетделатьдляглобальное хранилищеизодинключ,Так как у него нет других возможностей,Его нельзя копировать, выбрасывать,Или, как для хранилища без ключа, существует хранилище. поэтому,тыне могукопировать Монету нельзя потерять случайно Coin
public(общественныйиз)
,`public(friend)`[16],илиpublic(script)
。Чтосередина Последнее объяснениеэтотфункция Можетотторговля Скриптсерединанастраиватьиспользовать。public(script)
функциятакже Можетодеяло Что他public(script)
функциянастраиватьиспользовать。move_to
дапятьдругойизглобальное хранилище操делать符[17]№1。Сейчас существуют мы посмотрели на наш из Нет.один Move модуль,Давайте проведем тест,чтобы обеспечитьпроходить Изменять Оглавлениеприезжать`step_2/BasicCoin`[18],делатьчеканка монетяих期望изспособ работы。Move Модульные тесты в Rust Юнит-тесты в схожи, если вы с ними знакомы -- тестиспользовать#[test]
комментировать,И как обычный из Move Функции пишутся одинаково.
ты Можетиспользоватьpackage test
команда для запуска тестов。
move test
сейчассуществоватьпозволятьяихвзгляни`FirstModule.move`документ[19]изсодержание。ты Волясмотретьприезжатьэтот тест。
module 0xCAFE::BasicCoin {
...
// Declare a unit test. It takes a signer called `account` with an
// address value of `0xC0FFEE`.
#[test(account = @0xC0FFEE)]
fun test_mint_10(account: signer) acquires Coin {
let addr = 0x1::signer::address_of(&account);
mint(account, 10);
// Make sure there is a `Coin` resource under `addr` with a value of `10`.
// We can access this resource and its value since we are in the
// same module that defined the `Coin` resource.
assert!(borrow_global<Coin>(addr).value == 10, 0);
}
}
Это объявление файла с именем test_mint_10
из Модульное тестирование,существовать account
Внизкастингодин value
для 10
из Coin
Структура。Затем Проверить хранилищесерединаизмонетаданетиassert!
настраиватьиспользоватьиз Ожидаемое значение соответствует。если утверждение не выполнено,Юнит-тест завершится неудачей.
Move.toml
из[dependencies]
Частично добавленоодинзаписи для завершения,Например: [dependencies]
MoveStdlib = { local = `../../../../move-stdlib/`, addr_subst = { `std` = `0x1` } }
Уведомление,Возможно, вам придется изменить путь,указать на это<path_to_move>/language
Внизизmove-stdlib
Оглавление。тытакже Можетобозначение git иззависимость。ты Можетсуществоватьздесь[21]Читать далеео Move Содержимое зависимостей пакета.
11
,Тест не пройдет。попытаться найтиприезжатьодин Можетперешел кmove test
Заказизпараметр,Он покажет глобальный статус, если тест не пройден. Это должно выглядеть так: ┌── test_mint_10 ──────
│ error[E11001]: test failure
│ ┌─ ./sources/FirstModule.move:24:9
│ │
│ 18 │ fun test_mint_10(account: signer) acquires Coin {
│ │ ------------ In this function in 0xcafe::BasicCoin
│ ·
│ 24 │ assert!(borrow_global<Coin>(addr).value == 11, 0);
│ │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Test was not expected to abort but it aborted with 0 here
│
│
│ ────── Storage state at point of failure ──────
│ 0xc0ffee:
│ => key 0xcafe::BasicCoin::Coin {
│ value: 10
│ }
│
└──────────────────
move coverage
Заказ查смотреть Покрытиестатистикаиисточниккод Покрытие。BasicCoin
модульВ этом разделе мы разработаем реализацию, которая по сути Coin и Баланс интерфейсизмодуль, Монета Можетсуществоватьдругойадрес Вниздержатьиз Балансмеждукастингипередача。
Сигнатура публичной функции Move выглядит следующим образом:
/// Publish an empty balance resource under `account`'s address. This function must be called before
/// minting or transferring to the account.
public fun publish_balance(account: &signer) { ... }
/// кастинг `amount` tokens приезжать `mint_addr`. Нужен модульиз owner Авторизовать
public fun mint(module_owner: &signer, mint_addr: address, amount: u64) acquires Balance { ... }
/// возвращаться `owner` из Баланс
public fun balance_of(owner: address): u64 acquires Balance { ... }
/// Transfers `amount` of tokens from `from` to `to`.
public fun transfer(from: &signer, to: address, amount: u64) acquires Balance { ... }
Далее мы рассмотрим структуры данных, необходимые этому модулю.
один Move Модули не имеют собственного места для хранения. Напротив, двигаться из «Глобальное хранилище» (то, что мы называем нашим состоянием блокчейна) индексируется на основе адресов. Каждый адрес имеет Move модуль(код)и Move ресурс (ценность).
Глобальное хранилище в синтаксисе Rust выглядит примерно так.
struct GlobalStorage {
resources: Map<address, Map<ResourceType, ResourceValue>>
modules: Map<address, Map<ModuleName, ModuleBytecode>>
}
Рядом с каждым адресом Move Капиталисточникхранилищедаодиноттипприезжатьценитьизкартографирование。(одинхорош в наблюденииизчитатели могут Уведомлениеприезжать,этот意味着каждыйадресможет толькоиметькаждыйтипизодинценить)。Это удобнодляяих提供Понятноодинкадресдляиндексизместныйкартографирование。существоватьяихиз BasicCoin
модульсередина,яихопределение Понятнок Вниз Balance
Капиталисточник,Представляет каждый адрес, владеющий количеством монет.
/// Struct representing the balance of each address.
struct Balance has key {
coin: Coin // same Coin from Step 1
}
Грубо говоря, двигайтесь Статус блокчейна должен быть таким:
public(script)
функцияТолько сpublic(script)
видимостьизфункция Можетсуществоватьторговлясередина直接настраиватьиспользовать。потому чтоэтот,еслитыдуматьотторговлясередина直接настраиватьиспользоватьtransfer
метод,Вам необходимо изменить его подпись с из на для:
public(script) fun transfer(from: signer, to: address, amount: u64) acquires Balance { ... }
существоватьздесь[22]Читать далеео Move Видимость функции из описания.
На большинстве Ethereum ERC-20 договорсередина,каждыйадресиз Балансхранитсясуществоватьодинmapping(address => uint256)
типизпеременные состояниясередина。Эта переменная состояния хранитсуществовать Конкретные смарт-контрактыизхранилищесередина。
Состояние блокчейна Ethereum может выглядеть так:
BaseCoin
модульяих已经существоватьstep_4
в папкедлятысоздавать Понятноодин Move Сумка,имядляBasicCoin
。sources
документпапка Сумка Содержит Понятно Сумкасерединавсе Move модульизисточниккод,СумкавключатьBasicCoin.move
。существоватьэтот разделсередина,яих Воля仔细研究一Вниз`BasicCoin.move`[23]виз Реализация метода。
позволятьяихпервыйсуществовать`step_4/BasicCoin`[24]в папкебегатьк Вниз Заказ,пытатьсяделатьиспользовать Move Код сборки пакета.
move build
сейчассуществоватьпозволятьяих仔细взгляни`BasicCoin.move`[25]виз Реализация метода。
метод publish_balance
.
этотметодвыпускатьодинBalance
Капиталисточникприезжатьодин Данныйизадрес。потому чтодляэтот Капиталисточник需要проходитьмонетаили Перевести деньгиперенимать Coin,Местокpublish_balance
методдолжно бытьиспользоватьсемья(Сумкавключатьмодульвсе ВОЗ)существоватьперенимать coin звонил раньше.
этотметодделатьиспользоватьmove_to
操делать Приходитьвыпускать Капиталисточник。
let empty_coin = Coin { value: 0 };
move_to(account, Balance { coin: empty_coin });
метод mint
mint
методдляодин Данныйиз Счеткастинг Coin。здесьяих要求mint
Должно бытьприезжатьмодульвсе ВОЗиз Авторизовать。яихделатьиспользовать assert заявление для обеспечения исполнения.
assert!(signer::address_of(&module_owner) == MODULE_OWNER, errors::requires_address(ENOT_MODULE_OWNER));
Move серединаизутверждениезаявление Можеттакделатьиспользовать:assert! (<predicate>, <abort_code>);
。Это означает, что если<predicate>
для Фальшивый,那么Сразуиспользовать<abort_code>
серединаконецторговля。здесьMODULE_OWNER
иENOT_MODULE_OWNER
Вседасуществоватьмодульиз Начальное определениеизпостоянный。иerrors
модульопределение Понятнояих Можетделатьиспользоватьиз Распространенные категории ошибок。ценитьпридется Уведомлениеизда,Move существование является транзакционным во время исполнения из -- Местокесливнесейчасabort[26],Не нужно сбрасывать статус,потому чтодля Транзакцияиз Изменения не сохраняютсяприезжатьна блокчейне。
Затемяих Воляодинценаценитьдляamount
из Coin Депозитmint_addr
из Баланс。
deposit(mint_addr, Coin { value: amount });
**метод balance_of
**
яихделатьиспользоватьborrow_global
,Один из мировых операторов хранения,Чтение из глобального хранилища.
borrow_global<Balance>(owner).coin.value
| | \ /
resource type address field names
метод transfer
этотфункцияотfrom
из Баланссерединаизвлекать Токени Воля Токен Депозитto
из Баланссередина。яих仔细研究一Внизwithdraw
Вспомогательныйфункция:
fun withdraw(addr: address, amount: u64) : Coin acquires Balance {
let balance = balance_of(addr);
assert!(balance >= amount, EINSUFFICIENT_BALANCE);
let balance_ref = &mut borrow_global_mut<Balance>(addr).coin.value;
*balance_ref = balance - amount;
Coin { value: amount }
}
существоватьметодизначинать,яихутверждение Вывод денегиз Счетиметь достаточноиз Баланс。Затемяихделатьиспользоватьborrow_global_mut
получитьглобальное хранилищеизпеременный индексиспользовать,&mut
одеялоиспользовать Приходитьсоздаватьодин Структураизпеременный индексиспользовать[27]。Затемяихпроходитьэтотпеременный индексиспользовать Приходить修改余额,ивозвращатьсяодин С суммой выводаизновый Coin。
В нашем измодуле есть два «TODO», которые мы оставляем читателям как «дурапражняться».
publish_balance
метод。deposit
метод。этотупражнятьсяизрешение Можетсуществовать`step_4_sol`[28]документпапканайден в。
наградаупражняться
BasicCoin
модульиз Модульное тестированиесуществуют на этом этапе,Мы собираемся рассмотреть все различные модульные тесты, которые мы пишем.,Чтобы осветить наше существование Нет, напишите исходник в четыре шага. Мы также рассмотрим некоторые инструменты, которые можно использовать для написания тестов.
для работы,существовать`step_5/BasicCoin`[29]в папкебегатьpackage test
Заказ:
move test
тыотвечать Долженсмотретьприезжатьчто-то вроде этогоизвещь:
INCLUDING DEPENDENCY MoveStdlib
BUILDING BasicCoin
Running Move unit tests
[ PASS ] 0xcafe::BasicCoin::can_withdraw_amount
[ PASS ] 0xcafe::BasicCoin::init_check_balance
[ PASS ] 0xcafe::BasicCoin::init_non_owner
[ PASS ] 0xcafe::BasicCoin::publish_balance_already_exists
[ PASS ] 0xcafe::BasicCoin::publish_balance_has_zero
[ PASS ] 0xcafe::BasicCoin::withdraw_dne
[ PASS ] 0xcafe::BasicCoin::withdraw_too_much
Test result: OK. Total tests: 7; passed: 7; failed: 0
взгляни`BasicCoin`модуль[30]серединаизтест,Мы стараемся, чтобы каждый модульный тест существовал как отдельный тест из строки.
После прочтения теста,пытатьсясуществоватьBasicCoin
модульсередина Писатьодинимядляbalance_of_dne
из Модульное тестирование,тестсуществоватьbalance_of
одеялонастраиватьиспользоватьизадрес Вниз Не существуетсуществоватьBalance
Капиталисточникиз Состояние。Должно быть всего несколько строк!
этотупражнятьсяизрешение Можетсуществовать`step_5_sol`[31]попытаться найтиприезжать。
BasicCoin
модуль Стандартизациясуществовать Move середина,Мы можем использовать дженерики для определения различных типов входных данных, функций и структур. Дженерики — хороший строительный блок библиотек. существуют В этом разделе,яих Воляделать ПростойизBasicCoin
модульстановитьсядля Дженерики,Таким образом, его можно использовать как модуль для одиночного модуля.,Модуль используется другими пользователями.
Сначала мы добавляем параметры типа в структуру данных:
struct Coin<phantom CoinType> has store {
value: u64
}
struct Balance<phantom CoinType> has key {
coin: Coin<CoinType>
}
Аналогично добавьте параметры типа в метод. Например,withdraw
Изменятьстановиться Понятно Внизлапшаизсодержание:
fun withdraw<CoinType>(addr: address, amount: u64) : Coin<CoinType> acquires Balance {
let balance = balance_of<CoinType>(addr);
assert!(balance >= amount, EINSUFFICIENT_BALANCE);
let balance_ref = &mut borrow_global_mut<Balance<CoinType>>(addr).coin.value;
*balance_ref = balance - amount;
Coin<CoinType> { value: amount }
}
взгляни`step_6/BasicCoin/sources/BasicCoin.move`[32]Приходитьвзглянивесьизвыполнить。
существовать В этот момент,Познакомьтесь с Эфириумомизчитатели могут Уведомлениеприезжать,этотмодульиERC20 Стандарт токена[33]изглазизсходство,Для существования смарт-контракта предусмотрен один интерфейс для выбора взаимозаменяемых токенов. Ключевым преимуществом использования дженериков является возможность повторного использования.,Поскольку модуль общей библиотеки уже предоставляет один стандартный выбор,Экземплярный модуль может обеспечивать настройку путем упаковки стандартной выборки.
яих提供Понятноодинимядля`MyOddCoin`[34]из Маленькиймодуль,он создает экземплярCoin
типисделанный на заказ Понятно Чтопередача Стратегия:может толькопередачанечетное числоиз Coin。яих还Сумкавключатьдватест[35]Приходитьтестэтот ХОРОШОдля。ты Можетделатьиспользоватьтысуществовать Нет. 2 шаги Нет. 5 шагизучатьприезжатьиз Заказ Приходитьбегатьэтот些тест。
phantom
типпараметр
существоватьCoin
иBalance
изопределениесередина,яих声明типпараметрCoinType
даphantom
,потому чтодляCoinType
существовать Структураопределениесередина Нетделатьиспользовать,или ВОЗ只делатьдляphantom
Используются параметры типа.
здесь[36]Читать далееоphantom
типпараметризинформация。
существуют Прежде чем перейти к следующему шагу, давайте убедимся, что вы установили все зависимости извалидатора.
Попробуйте запуститьboogie /version
。есливнесейчас command not found: boogie
изошибкаинформация,Вам нужно будет запустить сценарий установки и применить файл конфигурации.
# run the following in move repo root directory
./scripts/dev_setup.sh -yp
source ~/.profile
Развертывание смарт-контрактов в блокчейне потенциально может манипулировать ценными активами. Метод, использующий строгую математику для описания поведения логических компьютерных систем и их правильности.,Формальная верификация уже используется в блокчейне,к防конец智能договорсерединаизошибка。The Move prover[37]даодин Постоянное развитиеиз Инструменты формальной проверки,использовать Виспользовать Move Язык для написания смарт-контрактов. Пользователи могут использовать Move Specification Language (MSL)[38]указать смарт-контрактыиз Функциональные атрибуты,Затем используйте валидатор, чтобы автоматически проверить их статически. для объясняет, как использовать валидатор,яихсуществоватьBasicCoin.move[39]серединаприсоединиться Понятнок Внизкодфрагмент。
spec balance_of {
pragma aborts_if_is_strict;
}
неофициально,кодкусокspec balance_of {...}
Сумка Содержитметодbalance_of
из Спецификация недвижимости。
позволятьяихпервыйсуществовать`BasicCoin`Оглавление[40]Внутриделатьиспользоватьк Вниз Заказбегатьвалидатор:
move prove
Выводится следующее сообщение об ошибке:
error: abort not covered by any of the `aborts_if` clauses
┌─ ./sources/BasicCoin.move:38:5
│
35 │ borrow_global<Balance<CoinType>>(owner).coin.value
│ ------------- abort happened here with execution failure
·
38 │ ╭ spec balance_of {
39 │ │ pragma aborts_if_is_strict;
40 │ │ }
│ ╰─────^
│
= at ./sources/BasicCoin.move:34: balance_of
= owner = 0x29
= at ./sources/BasicCoin.move:35: balance_of
= ABORTED
Error: exiting with verification errors
Валидатор в основном сообщает нам,яих需要明确обозначениефункцияbalance_of
Волясерединаконецизсостояние,этотдасуществоватьowner
Нетиметь КапиталисточникBalance<CoinType>
часнастраиватьиспользоватьфункцияborrow_global
делатьстановитьсяиз。для Понятноудалитьэтотошибкаинформация,яихдобавить в Понятноодинaborts_if
состояние,следующее:
spec balance_of {
pragma aborts_if_is_strict;
aborts_if !exists<Balance<CoinType>>(owner);
}
После добавления этого условия,снова Попробуйте запуститьprove
Заказ,чтобы подтвердить отсутствие ошибок проверки.
move prove
Помимо условия прерывания, мы также хотим определить функциональные свойства. существуют Нет. 8 На этом этапе мы определим BasicCoin
модульизметод Укажите атрибуты для соответствиявалидатор进ХОРОШОПодробнееизпредставлять。
BasicCoin
модуль Напишите формальную спецификациюметод withdraw
иззнакимясуществовать Внизлапша给вне:
fun withdraw<CoinType>(addr: address, amount: u64) : Coin<CoinType> acquires Balance
Долженметодотадресaddr
извлекатьценаценитьдляamount
из Токен,ивозвращатьсяодинсоздаватьизценаценитьдляamount
из Монета. когда 1)addr
Нет КапиталисточникBalance<CoinType>
или 2)addr
серединаиз Токенколичество Маленький Вamount
час,методwithdraw
серединаконец。яих Можеттакопределениесостояние。
spec withdraw {
let balance = global<Balance<CoinType>>(addr).coin.value;
aborts_if !exists<Balance<CoinType>>(addr);
aborts_if balance < amount;
}
какяихсуществоватьздесьсмотретьприезжатьиз,один блок спецификации может содержать привязки let,этодля Введение в выражениеимясказать。global<T>(address)。T
даодин Внутринаборфункция,возвращаться addr
виз Капиталисточникценить。balance
даaddr
Местоиметьиз Токенизколичество.exists<T>(address): bool
даодин Внутринаборфункция,если Капиталисточник T существоватьадресвжитьсуществовать,новозвращаться true。дваaborts_if
Пункт соответствует вышеуказанномуприезжатьиздвасостояние。Вообще говоря,еслиодинфункцияиметьодин Вот и всеизaborts_if
состояние,Эти условия будут согласованы друг с другом. По умолчанию,Если пользователь хочет указать условия прерывания,Необходимо перечислить все возможные условия. в противном случае,валидатор выдаст одну ошибку проверки. Однако,еслиpragma aborts_if_is_partial
существовать spec определяется в блоке, комбинация из условия прерывания (или-ed изодинокийсостояние)только означаетфункцияизсерединаконец。读ВОЗМожетссылкаMSL[41]документ Понятно Узнать большеинформация。
Следующим шагом является определение функциональных атрибутов, следующих двух: ensures
заявлениесерединаописывать。первый,проходитьделатьиспользоватьlet post
обязательность,balance_post
Указывает после выполненияaddr
из Баланс,этоотвечать Долженравныйbalance - amount
。Затем,возвращатьсяценить(выражатьдляresult
)отвечать Должендаодинценаценитьдляamount
из Coin。
spec withdraw {
let balance = global<Balance<CoinType>>(addr).coin.value;
aborts_if !exists<Balance<CoinType>>(addr);
aborts_if balance < amount;
let post balance_post = global<Balance<CoinType>>(addr).coin.value;
ensures balance_post == balance - amount;
ensures result == Coin<CoinType> { value: amount };
}
deposit
методметод deposit
иззнакимяследующее:
fun deposit<CoinType>(addr: address, check: Coin<CoinType>) acquires Balance
Метод будет check
Депозит addr
。Долженспецификацияопределениеследующее:
spec deposit {
let balance = global<Balance<CoinType>>(addr).coin.value;
let check_value = check.value;
aborts_if !exists<Balance<CoinType>>(addr);
aborts_if balance + check_value > MAX_U64;
let post balance_post = global<Balance<CoinType>>(addr).coin.value;
ensures balance_post == balance + check_value;
}
balance
Представляет перед выполнениемaddr
серединаиз Токенколичество,check_value
Представитель хочет Депозитиз Токенколичество.если 1)addr
Нет КапиталисточникBalance<CoinType>
или 2)balance
иcheck_value
Изибольше, чемu64
типизмаксимумценить,Метод будетпрекращение。Должен Функциональные атрибуты Проверить баланссуществовать После выполненияданетодеяло正确更новый。
transfer
методметод transfer
иззнакимяследующее:
public fun transfer<CoinType: drop>(from: &signer, to: address, amount: u64, _witness: CoinType) acquires Balance
Долженметодотfrom
из Счет Кto
изадреспередачаamount
из Монета. Инструкции следующие:
spec transfer {
let addr_from = signer::address_of(from);
let balance_from = global<Balance<CoinType>>(addr_from).coin.value;
let balance_to = global<Balance<CoinType>>(to).coin.value;
let post balance_from_post = global<Balance<CoinType>>(addr_from).coin.value;
let post balance_to_post = global<Balance<CoinType>>(to).coin.value;
ensures balance_from_post == balance_from - amount;
ensures balance_to_post == balance_to + amount;
}
addr_from
даfrom
изадрес。Затемпридетсяприезжатьaddr_from
иto
существоватьперед выполнениеми После выполненияиз Баланс。ensures
Положение о заявлении,отaddr_from
серединавычестьamount
из Токенколичество,идобавить вприезжатьto
середина。Однакои,валидатор выдаст следующее сообщение об ошибке.
error: post-condition does not hold
┌─ ./sources/BasicCoin.move:57:9
│
62 │ ensures balance_from_post == balance_from - amount;
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
│
...
когдаaddr_from
равныйto
час,Это имущество не удерживается. поэтому,яих Можетсуществоватьметод Добавитьодинутверждениеassert!(from_addr != to)
,чтобы обеспечитьaddr_from
Нетравныйto
。
transfer
методвыполнить aborts_if
состояние。mint
иpublish_balance
методизспецификация。этотупражнятьсяизрешение Можетсуществовать`step_8_sol`[42]попытаться найтиприезжать。
Исходный текст: https://github.com/move-language/move/tree/main/language/documentation/tutorial.
[1]
MoveMoon: https://learnblockchain.cn/people/11436
[2]
Move repository: https://github.com/move-language/move
[3]
README: https://github.com/move-language/move/tree/main/language/move-analyzer/editors/code
[4]
step_1/BasicCoin
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_1/BasicCoin
[5]
sources/FirstModule.move
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_1/BasicCoin/sources/FirstModule.move
[6]
Модуль: https://move-language.github.io/move/modules-and-scripts.html
[7]
Структура: https://move-language.github.io/move/structs-and-resources.html
[8]
signer
: https://move-language.github.io/move/signer.html
[9]
step_1/BasicCoin
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_1/BasicCoin
[10]
Move книга: https://move-language.github.io/move/packages.html
[11]
Переместить буклет и часть упаковки: https://move-language.github.io/move/packages.html#movetoml
[12]
Адрес именования: https://move-language.github.io/move/address.html#named-addresses
[13]
Структура: https://move-language.github.io/move/structs-and-resources.html
[14]
Способности: https://move-language.github.io/move/abilities.html
[15]
функция: https://move-language.github.io/move/functions.html
[16]
public(friend)
: https://move-language.github.io/move/friends.html
[17]
Пять различных глобальных операторов хранения: https://move-language.github.io/move/global-storage-operators.html
[18]
step_2/BasicCoin
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_2/BasicCoin
[19]
FirstModule.move
документ: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_2/BasicCoin/sources/FirstModule.move
[20]
здесь: https://github.com/move-language/move/blob/main/language/changes/4-unit-testing.md#testing-annotations-their-meaning-and-usage
[21]
здесь: https://move-language.github.io/move/packages.html#movetoml
[22]
здесь: https://move-language.github.io/move/functions.html#visibility
[23]
BasicCoin.move
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_4/sources/BasicCoin.move
[24]
step_4/BasicCoin
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_4/BasicCoin
[25]
BasicCoin.move
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_4/BasicCoin/sources/BasicCoin.move
[26]
abort: https://move-language.github.io/move/abort-and-assert.html
[27]
Изменяемая ссылка: https://move-language.github.io/move/references.html
[28]
step_4_sol
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_4_sol
[29]
step_5/BasicCoin
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_5/BasicCoin
[30]
BasicCoin
Модуль: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_5/BasicCoin/sources/BasicCoin.move
[31]
step_5_sol
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_5_sol
[32]
step_6/BasicCoin/sources/BasicCoin.move
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_6/BasicCoin/sources/BasicCoin.move
[33]
Стандарт токена ERC20: https://ethereum.org/en/developers/docs/standards/tokens/erc-20/
[34]
MyOddCoin
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_6/BasicCoin/sources/MyOddCoin.move
[35]
тест: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_6/BasicCoin/sources/MyOddCoin.move
[36]
здесь: https://move-language.github.io/move/generics.html#phantom-type-parameters
[37]
The Move prover: https://github.com/move-language/move/blob/main/language/move-prover/doc/user/prover-guide.md
[38]
Move Specification Language (MSL): https://github.com/move-language/move/blob/main/language/move-prover/doc/user/spec-lang.md
[39]
BasicCoin.move: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_7/BasicCoin/sources/BasicCoin.move
[40]
BasicCoin
Оглавление: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_7/BasicCoin
[41]
MSL: https://github.com/move-language/move/blob/main/language/move-prover/doc/user/spec-lang.md
[42]
step_8_sol
: https://github.com/solana-labs/move/blob/main/language/documentation/tutorial/step_8_sol