diff --git a/ru/1/arrays.md b/ru/1/arrays.md index c803136c07..95869d11f9 100644 --- a/ru/1/arrays.md +++ b/ru/1/arrays.md @@ -56,7 +56,7 @@ uint[] dynamicArray; Person[] people; // Динамический массив позволяет добавлять в него данные ``` -Ты не забыл, что переменные состояния сохраняются в блокчейне навсегда? Создание динамического массива из подобных структур полезно для хранения структурированных данных внутри контракта, как в базе данных. +Ты не забыл, что переменные состояния сохраняются в блокчейне навсегда? Создание динамического массива из подобных структур полезно для хранения структурированных данных внутри контракта, как в базе данных. ## Открытые массивы diff --git a/ru/1/arraysstructs2.md b/ru/1/arraysstructs2.md index 6ae0ca423b..91c5fe7f51 100644 --- a/ru/1/arraysstructs2.md +++ b/ru/1/arraysstructs2.md @@ -76,7 +76,7 @@ people.push(satoshi); people.push(Person(16, "Vitalik")); ``` -Обрати внимание, что `array.push()` обозначает конец массива, поэтому элементы выстраиваются в порядке добавления. Пример: +Обрати внимание, что `array.push()` обозначает конец массива, поэтому элементы выстраиваются в порядке добавления. Пример: ``` uint[] numbers; diff --git a/ru/1/contracts.md b/ru/1/contracts.md index b0c52d616c..56c21e445d 100644 --- a/ru/1/contracts.md +++ b/ru/1/contracts.md @@ -1,14 +1,14 @@ --- title: Контракты actions: ['Проверить', 'Подсказать'] -material: +material: editor: language: sol startingCode: | pragma solidity //1. Здесь укажи версию Solidity //2. Здесь создай контракт - answer: > + answer: > pragma solidity ^0.4.19; @@ -31,7 +31,7 @@ contract HelloWorld { ## Версия pragma -Любой код на Solidity начинается с «версии pragma» — объявления, с какой версией компилятора Solidity совместим код. Это делается для того, чтобы избежать проблем с будущими версиями компилятора, содержащими изменения и потенциально способными испортить код. +Любой код на Solidity начинается с «версии pragma» — объявления, с какой версией компилятора Solidity совместим код. Это делается для того, чтобы избежать проблем с будущими версиями компилятора, содержащими изменения и потенциально способными испортить код. Вот так: `pragma solidity ^0.4.19;` (на момент написания кода используется версия Solidity 0.4.19). diff --git a/ru/1/datatypes.md b/ru/1/datatypes.md index bf1ef0487e..003a205cb9 100644 --- a/ru/1/datatypes.md +++ b/ru/1/datatypes.md @@ -25,12 +25,12 @@ material: Отличная работа! Теперь, когда у нас есть оболочка контракта, мы можем изучить, как Solidity работает с переменными. -**_Переменные состояния_** записываются в хранилище контракта. Это означает, что они сохраняются в блокчейне Ethereum, как в базе данных. +**_Переменные состояния_** записываются в хранилище контракта. Это означает, что они сохраняются в блокчейне Ethereum, как в базе данных. ##### Пример: ``` contract Example { - // Контракт навсегда сохранен в блокчейне + // Контракт навсегда сохранен в блокчейне uint myUnsignedInteger = 100; } ``` @@ -45,6 +45,6 @@ contract Example { # Проверь себя -ДНК зомби будет определяться номером из 16 цифр. +ДНК зомби будет определяться номером из 16 цифр. Задай переменную состояния `uint` под названием `dnaDigits` (номер ДНК) и установи ее значение равным `16`. diff --git a/ru/1/events.md b/ru/1/events.md index c8349b286d..2ee002da5f 100644 --- a/ru/1/events.md +++ b/ru/1/events.md @@ -24,7 +24,7 @@ material: function _createZombie(string _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); // Здесь запусти событие - } + } function _generateRandomDna(string _str) private view returns (uint) { uint rand = uint(keccak256(_str)); @@ -58,7 +58,7 @@ material: function _createZombie(string _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; NewZombie(id, _name, _dna); - } + } function _generateRandomDna(string _str) private view returns (uint) { uint rand = uint(keccak256(_str)); @@ -75,7 +75,7 @@ material: Наш контракт почти готов! Осталось добавить **_событие_**. -**_Событие_** — это способ, которым контракт сообщает внешнему интерфейсу приложения, что в блокчейне произошло некое событие. Интерфейс может «услышать» определенные события и выполнить заданное действие по его наступлении. +**_Событие_** — это способ, которым контракт сообщает внешнему интерфейсу приложения, что в блокчейне произошло некое событие. Интерфейс может «услышать» определенные события и выполнить заданное действие по его наступлении. Пример: @@ -85,7 +85,7 @@ event IntegersAdded(uint x, uint y, uint result); function add(uint _x, uint _y) public { uint result = _x + _y; - // Запусти событие, чтобы оповестить приложение о вызове функции: + // Запусти событие, чтобы оповестить приложение о вызове функции: IntegersAdded(_x, _y, result); return result; } @@ -94,7 +94,7 @@ function add(uint _x, uint _y) public { Теперь внешний интерфейс приложения сможет услышать событие. Примерно так будет выглядеть выполнение JavaScript: ``` -YourContract.IntegersAdded(function(error, result) { +YourContract.IntegersAdded(function(error, result) { // Воспользуйся результатом } ``` @@ -105,6 +105,6 @@ YourContract.IntegersAdded(function(error, result) { 1. Задай `event` (событие) под названием `NewZombie` (новый зомби). Оно должно сообщать `zombieId` (`uint`), имя `name` (строку `string`) и ДНК `dna` (`uint`). -2. Измени функцию `_createZombie` (создать зомби) так, чтобы событие `NewZombie` запускалось после добавления нового солдата в массив `zombies`. +2. Измени функцию `_createZombie` (создать зомби) так, чтобы событие `NewZombie` запускалось после добавления нового солдата в массив `zombies`. 3. Тебе понадобится `id` — идентификатор зомби. `array.push()` возвращает `uint` новой длины массива. Поскольку первый элемент в массиве имеет индекс 0, `array.push () - 1` вернет индекс только что добавленного зомби. Сохрани результат `zombies.push () - 1` в `uint` с названием `id`, чтобы его можно было использовать в событии `NewZombie` в следующей строчке. diff --git a/ru/1/functions.md b/ru/1/functions.md index e8f7a4c3e5..273d1e6935 100644 --- a/ru/1/functions.md +++ b/ru/1/functions.md @@ -53,7 +53,7 @@ function eatHamburgers(string _name, uint _amount) { } ``` -Функция `eatHamburgers` (есть гамбургеры) берет два параметра: `string` и `uint`. Пока тело функции оставим пустым. +Функция `eatHamburgers` (есть гамбургеры) берет два параметра: `string` и `uint`. Пока тело функции оставим пустым. > Примечание: обычно (но не обязательно) имена переменных в параметрах функций записывают со знаком подчеркивания в начале, чтобы было проще отличить их от глобальных переменных. В наших урокам мы тоже будем пользоваться этим обычаем. @@ -69,4 +69,4 @@ eatHamburgers("vitalik", 100); 1. Создай функцию под названием `createZombie` (создать зомби), которая берет 2 параметра: **\_name** (имя, строка `string`) и **\_dna** (ДНК, тип `uint`). -Пока оставь тело функции пустым, мы заполним его позже. +Пока оставь тело функции пустым, мы заполним его позже. diff --git a/ru/1/functions2.md b/ru/1/functions2.md index 92e87b39e3..c59486bce1 100644 --- a/ru/1/functions2.md +++ b/ru/1/functions2.md @@ -47,7 +47,7 @@ material: } --- -По умолчанию функции в Solidity `public` (открытые): любой человек или контракт может вызвать и исполнить функцию твоего контракта. +По умолчанию функции в Solidity `public` (открытые): любой человек или контракт может вызвать и исполнить функцию твоего контракта. Разумеется, это не всегда желательно, потому что в контракте могут найтись уязвимости для атак. Лучше по умолчанию помечать функции как «закрытые» и потом задавать «открытые» функции, которые не страшно выставить на всеобщее обозрение. @@ -61,12 +61,12 @@ function _addToArray(uint _number) private { } ``` -Это означает, что только другие функции внутри контракта смогут вызвать и исполнить функцию добавления к массиву `numbers`. +Это означает, что только другие функции внутри контракта смогут вызвать и исполнить функцию добавления к массиву `numbers`. Как видишь, после имени функции идет ключевое слово `private`. Как и параметры, названия закрытых функций принято записывать, начиная со знака подчеркивания (`_`). # Проверь себя -На данный момент функция контракта `createZombie` (создать зомби) по умолчанию является открытой — любой может вызвать ее и создать зомби внутри нашего контакта! Давай закроем ее. +На данный момент функция контракта `createZombie` (создать зомби) по умолчанию является открытой — любой может вызвать ее и создать зомби внутри нашего контакта! Давай закроем ее. 1. Измени тип функции `createZombie` на закрытый. Не забудь записать имя функции так, как принято! diff --git a/ru/1/functions3.md b/ru/1/functions3.md index 9c6fbccb43..c3ebd5d1ee 100644 --- a/ru/1/functions3.md +++ b/ru/1/functions3.md @@ -44,7 +44,7 @@ material: function _createZombie(string _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); - } + } function _generateRandomDna(string _str) private view returns (uint) { @@ -53,11 +53,11 @@ material: } --- -В этом разделе мы изучим функцию **_вернуть значение_** и ее модификаторы. +В этом разделе мы изучим функцию **_вернуть значение_** и ее модификаторы. ## Вернуть значение -Как задать функцию, чтобы она возвращала значение: +Как задать функцию, чтобы она возвращала значение: ``` string greeting = "Привет, дружок"; @@ -87,16 +87,16 @@ function _multiply(uint a, uint b) private pure returns (uint) { } ``` -Функция даже не читает состояние приложения - она возвращает значение, которое зависит только от параметров самой функции. В этом случае мы задаем функцию как **_pure_**. +Функция даже не читает состояние приложения - она возвращает значение, которое зависит только от параметров самой функции. В этом случае мы задаем функцию как **_pure_**. -> Примечание: не всегда легко вспомнить, когда задать «чистую» функцию или «просмотр». К счастью, компилятор Solidity исправно выдает предупреждения, что нужно использовать тот или иной модификатор. +> Примечание: не всегда легко вспомнить, когда задать «чистую» функцию или «просмотр». К счастью, компилятор Solidity исправно выдает предупреждения, что нужно использовать тот или иной модификатор. # Проверь себя -Нам понадобится вспомогательная функция, которая генерирует случайный номер ДНК из строки. +Нам понадобится вспомогательная функция, которая генерирует случайный номер ДНК из строки. 1. Создай `private` (приватную) функцию под названием `_generateRandomDna` (сгенерировать случайную ДНК). Она будет брать один параметр под названием `_str` (строку `string`), и возвращать `uint`. -2. Эта функция будет просматривать определенные переменные в контракте, но не менять их. Присвой ей модификатор `view` (просмотр). +2. Эта функция будет просматривать определенные переменные в контракте, но не менять их. Присвой ей модификатор `view` (просмотр). -3. Тело функции по прежнему остается пустым, заполним его позже. +3. Тело функции по прежнему остается пустым, заполним его позже. diff --git a/ru/1/keccak256.md b/ru/1/keccak256.md index 96e42957ea..0e97892f4a 100644 --- a/ru/1/keccak256.md +++ b/ru/1/keccak256.md @@ -21,7 +21,7 @@ material: function _createZombie(string _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); - } + } function _generateRandomDna(string _str) private view returns (uint) { // Начало здесь @@ -46,7 +46,7 @@ material: function _createZombie(string _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); - } + } function _generateRandomDna(string _str) private view returns (uint) { uint rand = uint(keccak256(_str)); @@ -56,11 +56,11 @@ material: } --- -Нужно, чтобы функция `_generateRandomDna` (сгенерировать случайную ДНК) возвращала (полу-) случайный `uint`. Как этого добиться? +Нужно, чтобы функция `_generateRandomDna` (сгенерировать случайную ДНК) возвращала (полу-) случайный `uint`. Как этого добиться? -В Ethereum есть встроенная хэш-функция `keccak256` (произносится как «кечак»), разновидность SHA3. Хеш-функция обычно преображает входную строку в случайное 256-битное шестнадцатеричное число. Небольшое изменение в строке приведет к сильному изменению хэша. +В Ethereum есть встроенная хэш-функция `keccak256` (произносится как «кечак»), разновидность SHA3. Хеш-функция обычно преображает входную строку в случайное 256-битное шестнадцатеричное число. Небольшое изменение в строке приведет к сильному изменению хэша. -Эта функция полезна для выполнения многих задач в Ethereum, но сейчас мы используем ее для обычной генерации псевдослучайных чисел. +Эта функция полезна для выполнения многих задач в Ethereum, но сейчас мы используем ее для обычной генерации псевдослучайных чисел. Пример: @@ -71,30 +71,30 @@ keccak256("aaaab"); keccak256("aaaac"); ``` -Как видишь, функция возвращает абсолютно другое значение, хотя мы изменили всего одну входную букву. +Как видишь, функция возвращает абсолютно другое значение, хотя мы изменили всего одну входную букву. -> Примечание: в блокчейне остро стоит проблема генерации **безопасных** случайных чисел. Приведенный нами метод небезопасен, но для текущей задачи годится, поскольку безопасность не входит в приоритетные задачи ДНК зомби. +> Примечание: в блокчейне остро стоит проблема генерации **безопасных** случайных чисел. Приведенный нами метод небезопасен, но для текущей задачи годится, поскольку безопасность не входит в приоритетные задачи ДНК зомби. ## Преобразование типов данных -Периодически типы данных надо конвертировать. Смотри пример: +Периодически типы данных надо конвертировать. Смотри пример: ``` uint8 a = 5; uint b = 6; // Выдаст ошибку, потому что a * b возвращает uint, а не uint8: -uint8 c = a * b; +uint8 c = a * b; // Чтобы код работал, нужно преобразовать b в uint8: -uint8 c = a * uint8(b); +uint8 c = a * uint8(b); ``` -В примере выше `a * b` возвращал `uint`, но мы попытались сохранить его как `uint8`, что потенциально могло привести к проблемам. Если преобразовать тип данных в `uint8`, то код будет работать, а компилятор не выдаст ошибку. +В примере выше `a * b` возвращал `uint`, но мы попытались сохранить его как `uint8`, что потенциально могло привести к проблемам. Если преобразовать тип данных в `uint8`, то код будет работать, а компилятор не выдаст ошибку. # Проверь себя -Давай заполним тело функции `_generateRandomDna` (сгенерировать случайную ДНК)! Для этого: +Давай заполним тело функции `_generateRandomDna` (сгенерировать случайную ДНК)! Для этого: 1. Первая строчка кода должна взять `keccak256`-хэш от `_str`, чтобы сгенерировать превдослучайное шестнадцатеричное - число, преобразовать его в `uint` и сохранить результат в `uint` с именем `rand`. + число, преобразовать его в `uint` и сохранить результат в `uint` с именем `rand`. 2. Мы хотим, чтобы зомби-ДНК содержала только 16 цифр (помнишь `dnaModulus`?). Поэтому следующая строчка кода должна `return` (возвращать) вычисленное выше значение модуля (`%`) `dnaModulus`. diff --git a/ru/1/lessoncomplete.md b/ru/1/lessoncomplete.md index 1721ef76dc..47763e2f4d 100644 --- a/ru/1/lessoncomplete.md +++ b/ru/1/lessoncomplete.md @@ -14,8 +14,8 @@ material: ### 1. Войди, чтобы сохранить прогресс -**_Войди_** и нажми «Сохранить прогресс» вверху страницы. Как только появится новый урок, мы сразу дадим тебе знать. +**_Войди_** и нажми «Сохранить прогресс» вверху страницы. Как только появится новый урок, мы сразу дадим тебе знать. ### 2. Поделись зомби с друзьями -**_Поделиться_** зомби в Твитере и все такое (Вставить изображение / ссылку) +**_Поделиться_** зомби в Твитере и все такое (Вставить изображение / ссылку) diff --git a/ru/1/lessonoverview.md b/ru/1/lessonoverview.md index 01337466bc..948941c6d9 100644 --- a/ru/1/lessonoverview.md +++ b/ru/1/lessonoverview.md @@ -10,25 +10,25 @@ material: answer: 1 --- -В Уроке 1 ты создашь «Фабрику Зомби» с целью собрать зомби-армию. +В Уроке 1 ты создашь «Фабрику Зомби» с целью собрать зомби-армию. * Фабрика будет содержать данные всех зомби в армии * У фабрики будет функция создания новых зомби * У каждого зомби будет случайный уникальный внешний вид -В следующих уроках мы добавим больше функционала, например, сделаем так, чтобы зомби мог нападать на людей и других зомби! Но пока мы будем добираться до этого момента, напишем базовый функционал создания новых зомби. +В следующих уроках мы добавим больше функционала, например, сделаем так, чтобы зомби мог нападать на людей и других зомби! Но пока мы будем добираться до этого момента, напишем базовый функционал создания новых зомби. -## Как устроена ДНК зомби +## Как устроена ДНК зомби -Внешний вид зомби обусловлен его ДНК. ДНК зомби — простое целое число из 16 цифр, например: +Внешний вид зомби обусловлен его ДНК. ДНК зомби — простое целое число из 16 цифр, например: ``` 8356281049284737 ``` -Как и в настоящей ДНК, различные части этого числа будут отражать специфические черты. Первые две цифры определяют внешний вид головы зомби, следующие две — разрез глаз и так далее. +Как и в настоящей ДНК, различные части этого числа будут отражать специфические черты. Первые две цифры определяют внешний вид головы зомби, следующие две — разрез глаз и так далее. -> Примечание: это сильно упрощенный урок, поэтому у зомби возможно только 7 разных типов голов (хотя из 2 цифр можно получить 100 возможных вариантов). Если мы захотим увеличить число вариантов зомби, то потом добавим больше типов голов. +> Примечание: это сильно упрощенный урок, поэтому у зомби возможно только 7 разных типов голов (хотя из 2 цифр можно получить 100 возможных вариантов). Если мы захотим увеличить число вариантов зомби, то потом добавим больше типов голов. Например, первые 2 цифры зомби-ДНК, приведенной выше, равны `83`. Чтобы определить тип головы зомби, мы выполняем операцию `83 % 7 + 1` = 7. Этот зомби получит седьмой тип головы. @@ -36,6 +36,6 @@ material: # Попробуй! -1. Поиграй со слайдером в правой части страницы и увидишь, как различные цифровые комбинации соответствуют разным аспектам внешнего вида зомби. +1. Поиграй со слайдером в правой части страницы и увидишь, как различные цифровые комбинации соответствуют разным аспектам внешнего вида зомби. -Ладно, поигрались и хватит. Когда надоест, нажми на кнопку «Следующая глава» внизу страницы, и погрузись в изучение Solidity целиком! +Ладно, поигрались и хватит. Когда надоест, нажми на кнопку «Следующая глава» внизу страницы, и погрузись в изучение Solidity целиком! diff --git a/ru/1/puttingittogether.md b/ru/1/puttingittogether.md index 10a5474600..7b7e432a68 100644 --- a/ru/1/puttingittogether.md +++ b/ru/1/puttingittogether.md @@ -21,7 +21,7 @@ material: function _createZombie(string _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); - } + } function _generateRandomDna(string _str) private view returns (uint) { uint rand = uint(keccak256(_str)); @@ -49,7 +49,7 @@ material: function _createZombie(string _name, uint _dna) private { zombies.push(Zombie(_name, _dna)); - } + } function _generateRandomDna(string _str) private view returns (uint) { uint rand = uint(keccak256(_str)); @@ -66,7 +66,7 @@ material: Мы почти закончили с генератором случайных зомби! Давай создадим публичную функцию, которая объединит в себе все сделанное ранее. -Создадим публичную функцию, которая получает на вход параметр имя зомби и использует его, чтобы создать зомби со случайной ДНК. +Создадим публичную функцию, которая получает на вход параметр имя зомби и использует его, чтобы создать зомби со случайной ДНК. # Проверь себя diff --git a/ru/1/structs.md b/ru/1/structs.md index 55f0fa2890..dbb33ec0fd 100644 --- a/ru/1/structs.md +++ b/ru/1/structs.md @@ -48,7 +48,7 @@ struct Person { # Проверь себя -Мы собираемся создать зомби! У них будет несколько свойств, поэтому структура подойдет как нельзя лучше. +Мы собираемся создать зомби! У них будет несколько свойств, поэтому структура подойдет как нельзя лучше. 1. Создай `struct` (структуру) с именем `Zombie`. diff --git a/ru/1/web3js.md b/ru/1/web3js.md index f039bcc56e..607a489b49 100644 --- a/ru/1/web3js.md +++ b/ru/1/web3js.md @@ -10,13 +10,13 @@ material: answer: 1 --- -Наш контракт Solidity готов! Теперь напишем внешний интерфейс JavaScript, который будет взаимодействовать с контрактом. +Наш контракт Solidity готов! Теперь напишем внешний интерфейс JavaScript, который будет взаимодействовать с контрактом. В Ethereum есть библиотека JavaScript под названием **_Web3.js_**. -В следующем уроке мы подробно изучим, как развернуть контракт и настроить Web3.js. А сейчас просто посмотрим, как Web3.js будет взаимодействовать с развернутым контрактом. +В следующем уроке мы подробно изучим, как развернуть контракт и настроить Web3.js. А сейчас просто посмотрим, как Web3.js будет взаимодействовать с развернутым контрактом. -Не беспокойся, если пока не все понятно. +Не беспокойся, если пока не все понятно. ``` // Как осуществляется доступ к контракту: @@ -26,7 +26,7 @@ var contractAddress = /* our contract address on Ethereum after deploying */ var ZombieFactory = ZombieFactoryContract.at(contractAddress) // `ZombieFactory` получил доступ к открытым функциям и событиям -// «Слушатель» событий принимает введенный текст +// «Слушатель» событий принимает введенный текст $("#ourButton").click(function(e) { var name = $("#nameInput").val() // Вызываем функцию контракта `createRandomZombie`: @@ -39,10 +39,10 @@ var event = ZombieFactory.NewZombie(function(error, result) { generateZombie(result.zombieId, result.name, result.dna) }) -// Возьмем ДНК зомби и обновим изображение +// Возьмем ДНК зомби и обновим изображение function generateZombie(id, name, dna) { let dnaStr = String(dna) - // Заполним ячейки нулями, если ДНК получилось меньше 16 знаков + // Заполним ячейки нулями, если ДНК получилось меньше 16 знаков while (dnaStr.length < 16) dnaStr = "0" + dnaStr @@ -66,10 +66,10 @@ function generateZombie(id, name, dna) { } ``` -В результате JavaScript берет значения, сгенерированные в `zombieDetails`, и применяет «браузерную магию» JavaScript (мы используем Vue.js), чтобы изменить изображения и примененить CSS-фильтр. В следующем уроке ты увидишь код целиком. +В результате JavaScript берет значения, сгенерированные в `zombieDetails`, и применяет «браузерную магию» JavaScript (мы используем Vue.js), чтобы изменить изображения и примененить CSS-фильтр. В следующем уроке ты увидишь код целиком. # Попробуй! -Вперед! Напиши свое имя в правом поле и увидишь, какой получится зомби! +Вперед! Напиши свое имя в правом поле и увидишь, какой получится зомби! **Как только получишь зомби, который тебе нравится, жми на кнопку «Следующий раздел». Ты сохранишь зомби и завершишь урок 1!** diff --git a/ru/2/1-overview.md b/ru/2/1-overview.md index 59e65e7156..47e3ce46d1 100644 --- a/ru/2/1-overview.md +++ b/ru/2/1-overview.md @@ -15,7 +15,7 @@ material: Во втором уроке мы займемся геймифицикацией приложение: добавим многопользовательский режим, а вместо простой случайной генерации сделаем создание зомби более разнообразным. -Как же теперь будут появляться новые зомби? Мы заставим старых зомби питаться другими формами жизни! +Как же теперь будут появляться новые зомби? Мы заставим старых зомби питаться другими формами жизни! ## Питание зомби @@ -23,13 +23,13 @@ material: Кем зомби любят питаться больше всего? -Закончи Урок 2 и узнаешь! +Закончи Урок 2 и узнаешь! # Попробуй! Справа — простая демонстрация того, как питается зомби! Кликни на человека, и увидишь что будет, когда зобми его сожрет! -Видишь, ДНК зомби определяется собсвенной ДНК зомби и ДНК съеденного человека. +Видишь, ДНК зомби определяется собсвенной ДНК зомби и ДНК съеденного человека. Когда захочешь двигаться дальше, кликай на «Следующая глава», и приступим к созданию многопользовательского режима. diff --git a/ru/2/10-interactingcontracts.md b/ru/2/10-interactingcontracts.md index 387b28de0d..b006a1ce2a 100644 --- a/ru/2/10-interactingcontracts.md +++ b/ru/2/10-interactingcontracts.md @@ -111,7 +111,7 @@ material: Чтобы наш контракт связался с другим контрактом в блокчейне, которым владеем не мы, сначала нужно определить **_интерфейс_**. -Посмотрим простой пример. Допустим, в блокчейне существует такой контракт: +Посмотрим простой пример. Допустим, в блокчейне существует такой контракт: ``` contract LuckyNumber { diff --git a/ru/2/11-interactingcontracts2.md b/ru/2/11-interactingcontracts2.md index faf7eea108..103d04c9da 100644 --- a/ru/2/11-interactingcontracts2.md +++ b/ru/2/11-interactingcontracts2.md @@ -28,7 +28,7 @@ material: contract ZombieFeeding is ZombieFactory { address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d; - // Здесь запусти контракт котика, взяв сверху `ckAddress` + // Здесь запусти контракт котика, взяв сверху `ckAddress` function feedAndMultiply(uint _zombieId, uint _targetDna) public { require(msg.sender == zombieToOwner[_zombieId]); @@ -125,7 +125,7 @@ contract NumberInterface { Мы можем использовать его в контракте следующим образом: ``` contract MyContract { - address NumberInterfaceAddress = 0xab38... + address NumberInterfaceAddress = 0xab38... // ^ Адрес контракта FavoriteNumber в Ethereum NumberInterface numberContract = NumberInterface(NumberInterfaceAddress) // Сейчас `numberContract` указывает на другие контракты @@ -138,7 +138,7 @@ contract MyContract { } ``` -Этим способом контракт будет взаимодействовать с всеми другими контрактами в блокчейне Ethereum, если они задают функции как `public` (открытые) или `external` (внешние). +Этим способом контракт будет взаимодействовать с всеми другими контрактами в блокчейне Ethereum, если они задают функции как `public` (открытые) или `external` (внешние). # Проверь себя diff --git a/ru/2/12-multiplereturns.md b/ru/2/12-multiplereturns.md index 433912bc1b..733a5bca78 100644 --- a/ru/2/12-multiplereturns.md +++ b/ru/2/12-multiplereturns.md @@ -147,7 +147,7 @@ function getLastReturnValue() external { # Проверь себя -Пробил час начала взаимодействия с контрактом Криптокотиков! +Пробил час начала взаимодействия с контрактом Криптокотиков! Создадим функцию, которая получает гены котика из контракта: diff --git a/ru/2/13-kittygenes.md b/ru/2/13-kittygenes.md index 475ec3b707..296faa441f 100644 --- a/ru/2/13-kittygenes.md +++ b/ru/2/13-kittygenes.md @@ -30,13 +30,13 @@ material: address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d; KittyInterface kittyContract = KittyInterface(ckAddress); - // Здесь измени значение функции: + // Здесь измени определение функции: function feedAndMultiply(uint _zombieId, uint _targetDna) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; - // А здесь добавь оператор «если»: + // А здесь добавь оператор «если»: _createZombie("NoName", newDna); } @@ -133,13 +133,13 @@ material: } --- -Мы закончили с логикой функции... но давай добавим небольшую бонусную фишку. +Мы закончили с логикой функции... но давай добавим небольшую бонусную фишку. Сделаем так, чтобы зомби, полученные из котиков, обладали уникальной характеристику, показывающей, что они именно зомбокотики. -Для этого добавим специальный котиковый код в ДНК зомби. +Для этого добавим специальный котиковый код в ДНК зомби. -Если помнишь, в первом уроке мы использовали только первые 12 цифр из 16-циферного ДНК, чтобы определить внешний вид зомби. Поэтому давай возьмем последние 2 цифры из неиспользованных, чтобы разобраться со «специальными» характеристиками. +Если помнишь, в первом уроке мы использовали только первые 12 цифр из 16-циферного ДНК, чтобы определить внешний вид зомби. Поэтому давай возьмем последние 2 цифры из неиспользованных, чтобы разобраться со «специальными» характеристиками. Допустим, последние две цифры ДНК зомбокотика `99` (ведь известно, что у кошки 9 жизней). В нашем коде, `if` (если) зомби происходит от котика, то последние две цифры в ДНК мы установим как `99`. diff --git a/ru/3/00-overview.md b/ru/3/00-overview.md index c07007a7a7..6ca847e368 100644 --- a/ru/3/00-overview.md +++ b/ru/3/00-overview.md @@ -1,5 +1,5 @@ --- -title: Продвинутые концепции Solidity +title: Продвинутые концепции Solidity header: "Урок 3: Продвинутые концепции Solidity" roadmap: roadmap3.png --- diff --git a/ru/3/01-externaldependencies.md b/ru/3/01-externaldependencies.md index 1acdd7f6e5..b55f4facc0 100644 --- a/ru/3/01-externaldependencies.md +++ b/ru/3/01-externaldependencies.md @@ -151,13 +151,13 @@ material: ## Внешние зависимости -Во втором уроке мы зашили адрес контракта Криптокотиков в DApp. Но что произойдет, если в контракте Криптокотиков обнаружится баг или кто-то уничтожит всех котиков? +Во втором уроке мы зашили адрес контракта Криптокотиков в DApp. Но что произойдет, если в контракте Криптокотиков обнаружится баг или кто-то уничтожит всех котиков? Это маловероятно, но если вдруг подобное произойдет, то наш DApp станет совершенно бесполезным - он будет указывать на адрес, который больше не возвращает котиков. Зомби не смогут питаться котятами, а мы не сможем починить контракт. По этой причине имеет смысл предустмотреть функции, позволяющие обновлять ключевые части DApp. -Например, вместо того, чтобы зашивать адрес контракта Криптокотиков в DApp, лучше предусмотреть функцию `setKittyContractAddress` (задать адрес котоконтракта). Если в контракте Криптокотиков что-то пойдет не так, она позволит в будущем изменить адрес. +Например, вместо того, чтобы зашивать адрес контракта Криптокотиков в DApp, лучше предусмотреть функцию `setKittyContractAddress` (задать адрес котоконтракта). Если в контракте Криптокотиков что-то пойдет не так, она позволит в будущем изменить адрес. ## Проверь себя @@ -167,8 +167,8 @@ material: 2. Там, где мы создали `kittyContract`, измени строчку и просто объяви переменную, не задавая ее равной чему-либо. -3. Создай функцию под названием `setKittyContractAddress`. Она берет аргумент `_address` (адрес). Это должна быть внешняя функция. +3. Создай функцию под названием `setKittyContractAddress`. Она берет аргумент `_address` (адрес). Это должна быть внешняя функция. 4. Внутри функции добавь строчку кода, которая устанавливает `kittyContract` равной `KittyInterface(_address)`. -> Примечание: если заметишь дыру в безопасности этой функции, не волнуйся — мы пофиксим ее в следующей главе ;) +> Примечание: если заметишь дыру в безопасности этой функции, не волнуйся — мы пофиксим ее в следующей главе ;) diff --git a/ru/3/02-ownable.md b/ru/3/02-ownable.md index 933f47c58f..f793d769de 100644 --- a/ru/3/02-ownable.md +++ b/ru/3/02-ownable.md @@ -191,7 +191,7 @@ material: Ниже пример `Ownable` контракта из библиотеки Solidity **_OpenZeppelin_**. OpenZeppelin - это библиотека безопасных смарт-контрактов сообщества, которыми можно пользоваться для личных DApps. Пока ты будешь ждать Урока 4, посмотри библиотеки на этом сайте. Поможет в дальнейшем. -Прочитай контракт ниже. Ты увидишь несколько неизученных моментов, не волнуйся, сейчас мы поговорим о них. +Прочитай контракт ниже. Ты увидишь несколько неизученных моментов, не волнуйся, сейчас мы поговорим о них. ``` /** @@ -235,23 +235,23 @@ contract Ownable { - Конструкторы: `function Ownable()` это **_конструктор_**, особая опциональная функция с таким же именем, как контракт. Выполняется только один раз в момент создания контракта. - Модификаторы функции: `modifier onlyOwner()`. Модификаторы — полуфункции, которые используются для изменения других функций, обычно для проверки некоторых требований до их выполнения. В этом случае `onlyOwner` можно использовать для ограничения доступа, чтобы **только владелец** контракта мог запустить эту функцию. В следующей главе мы подробно поговорим о модификаторах функций, а также о странном `_;` и его назначении. -- Ключевое слово `indexed`: пока не нужно, об этом потом. +- Ключевое слово `indexed`: пока не нужно, об этом потом. В целом `Ownable` контракт делает следующее: 1. Когда контракт создается, конструктор присваивает `msg.sender` (развернувшему контракт) атрибут `owner`. -2. Он добавляет модификатор `onlyOwner`, который может ограничить доступ к определенным функциям, предоставив его только владельцу `owner`. +2. Он добавляет модификатор `onlyOwner`, который может ограничить доступ к определенным функциям, предоставив его только владельцу `owner`. 3. Он позволяет передать контракт новому `owner`. -`onlyOwner` настолько распространенное требование для контрактов, что большинство DApps Solidity начинаются с копирования/вставки `Ownable` контракта, а следующий контракт наследует ему. +`onlyOwner` настолько распространенное требование для контрактов, что большинство DApps Solidity начинаются с копирования/вставки `Ownable` контракта, а следующий контракт наследует ему. Поскольку мы хотим ограничить `setKittyContractAddress` только для `onlyOwner`, сделаем то же самое и для нашего контракта. ## Проверь себя -Мы скопировали код контракта `Ownable` в новый файл `ownable.sol`. Продолжи, сделав так, чтобы `ZombieFactory` наследовал ему. +Мы скопировали код контракта `Ownable` в новый файл `ownable.sol`. Продолжи, сделав так, чтобы `ZombieFactory` наследовал ему. 1. Модифицируй код таким образом, чтобы импортировать (`import`) контент в `ownable.sol`. Если не помнишь как, взгляни на `zombiefeeding.sol`. diff --git a/ru/3/04-gas.md b/ru/3/04-gas.md index 10dc772d2b..fb0b514b93 100644 --- a/ru/3/04-gas.md +++ b/ru/3/04-gas.md @@ -201,7 +201,7 @@ Ethereum похож на большой, медленный, но крайне ## Как упаковать структуру, сэкономив газ -Мы упоминали в первом уроке, что есть разные типы `uint`: `uint8`, `uint16`, `uint32` и так далее. +Мы упоминали в первом уроке, что есть разные типы `uint`: `uint8`, `uint16`, `uint32` и так далее. Обычно использование этих подтипов нецелесообразно, поскольку Solidity резервирует 256 бит в хранилище независимо от размера `uint`. Например, использование `uint8` вместо `uint` (`uint256`) не экономит газ. @@ -224,7 +224,7 @@ struct MiniMe { // `mini` будет стоить меньше, чем `normal` из-за упаковки структуры NormalStruct normal = NormalStruct(10, 20, 30); -MiniMe mini = MiniMe(10, 20, 30); +MiniMe mini = MiniMe(10, 20, 30); ``` Так что внутри структур можно использовать наименьшие целочисленные подтипы, которые позволяют запустить код. @@ -233,7 +233,7 @@ MiniMe mini = MiniMe(10, 20, 30); ## Проверь себя -В этом уроке мы собираемся добавить зомби две новые фишки: `level` (уровень) и `readyTime` (время готовности) — последняя будет использоваться для установки времени перезарядки, чтобы ограничить частоту питания зомби. +В этом уроке мы собираемся добавить зомби две новые фишки: `level` (уровень) и `readyTime` (время готовности) — последняя будет использоваться для установки времени перезарядки, чтобы ограничить частоту питания зомби. Вернемся назад к `zombiefactory.sol`. diff --git a/ru/3/05-timeunits.md b/ru/3/05-timeunits.md index b51682731f..e0e693f818 100644 --- a/ru/3/05-timeunits.md +++ b/ru/3/05-timeunits.md @@ -191,9 +191,9 @@ material: ## Единицы времени -В Solidity есть собственные единицы для управления временем. +В Solidity есть собственные единицы для управления временем. -Переменная `now` вернет текущую временную метку unix (количество секунд, прошедших с 1 января 1970 года). Время этой записи по unix - `1515527488`. +Переменная `now` вернет текущую временную метку unix (количество секунд, прошедших с 1 января 1970 года). Время этой записи по unix - `1515527488`. > Примечание. Unix-время традиционно сохраняется в 32-битном номере. Это приведет к проблеме «2038 года», когда 32-разрядные временные метки unix переполнят и сломают множество устаревших систем. Поэтому, если мы хотим, чтобы наш DApp продолжал работать и через 20 лет, желательно было бы использовать 64-битное число. Но пользователям пришлось бы тратить больше газа для работы DApp. Есть над чем поломать голову! @@ -232,4 +232,4 @@ function fiveMinutesHavePassed() public view returns (bool) { `now + cooldownTime` будет равняться (в секундах) текущему отрезку времени unix плюс количеству секунд в одном дне, что в свою очередь будет равняться отрезку времени через 1 день от текущего момента. Потом мы сравним `readyTime` зомби и `now`. Если оно больше, то зомби снова можно использовать. -В следующей главе мы реализуем функционал ограничения действий на основе `readyTime`. +В следующей главе мы реализуем функционал ограничения действий на основе `readyTime`. diff --git a/ru/3/06-zombiecooldowns.md b/ru/3/06-zombiecooldowns.md index 9337d05379..ca31291022 100644 --- a/ru/3/06-zombiecooldowns.md +++ b/ru/3/06-zombiecooldowns.md @@ -34,7 +34,7 @@ material: kittyContract = KittyInterface(_address); } - // 1. Здесь задать функцию `_triggerCooldown` + // 1. Здесь задать функцию `_triggerCooldown` // 2. Здесь задать функцию `_isReady` diff --git a/ru/3/07-zombiecooldowns2.md b/ru/3/07-zombiecooldowns2.md index 597937e062..21b7979f6e 100644 --- a/ru/3/07-zombiecooldowns2.md +++ b/ru/3/07-zombiecooldowns2.md @@ -46,7 +46,7 @@ material: function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public { require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; - // 2. Здесь добавь проверку `_isReady` + // 2. Здесь добавь проверку `_isReady` _targetDna = _targetDna % dnaModulus; uint newDna = (myZombie.dna + _targetDna) / 2; if (keccak256(_species) == keccak256("kitty")) { diff --git a/ru/3/10-savinggasview.md b/ru/3/10-savinggasview.md index 8d28f7894a..a64eea019b 100644 --- a/ru/3/10-savinggasview.md +++ b/ru/3/10-savinggasview.md @@ -28,7 +28,7 @@ material: zombies[_zombieId].dna = _newDna; } - // Здесь создай функцию + // Здесь создай функцию } @@ -192,7 +192,7 @@ material: } --- -Круто! Теперь у нас есть специальные возможности для высокоуровневых зомби, так владельцам будет интересно поднимать уровень. Позже при желании можно добавить больше специальных возможностей. +Круто! Теперь у нас есть специальные возможности для высокоуровневых зомби, так владельцам будет интересно поднимать уровень. Позже при желании можно добавить больше специальных возможностей. Добавим еще одну функцию: нужен способ, чтобы в DApp увидеть всю свою армию зомби. Назовем ее `getZombiesByOwner`. diff --git a/ru/3/13-wrappingitup.md b/ru/3/13-wrappingitup.md index 6eebd653dc..6e8e3c7a84 100644 --- a/ru/3/13-wrappingitup.md +++ b/ru/3/13-wrappingitup.md @@ -15,17 +15,17 @@ material: ## Напомним: -- Мы добавили способ обновления адреса контракта Криптокотиков +- Мы добавили способ обновления адреса контракта Криптокотиков - Мы научились защищать основные функции с помощью `onlyOwner` - Мы узнали о газе и его оптимизации -- Добавили уровни и время перезарядки для зомби -- Сейчас у нас есть функция изменения имени и ДНК при достижении зомби определенного уровня -- И, наконец, теперь у нас есть функция возврата всей зомби-армии +- Добавили уровни и время перезарядки для зомби +- Сейчас у нас есть функция изменения имени и ДНК при достижении зомби определенного уровня +- И, наконец, теперь у нас есть функция возврата всей зомби-армии ## Тебе положен подарок! -В качестве вознаграждения за завершение Урока 3 оба твоих зомби получают новый уровень! +В качестве вознаграждения за завершение Урока 3 оба твоих зомби получают новый уровень! Теперь, когда безымянный зомбокотик из Урока 2 получил уровень, ты можешь вызвать `changeName` и назвать его как тебе нравится. Хватит ноунеймов! -Вперед! Дай имя зомби и двигайся к следующему разделу, чтобы закончить урок. +Вперед! Дай имя зомби и двигайся к следующему разделу, чтобы закончить урок. diff --git a/ru/4/battle-03.md b/ru/4/battle-03.md index f025608c04..9ac10be18c 100644 --- a/ru/4/battle-03.md +++ b/ru/4/battle-03.md @@ -13,7 +13,7 @@ material: contract ZombieBattle is ZombieHelper { uint randNonce = 0; - // Здесь создай attackVictoryProbability + // Здесь создай attackVictoryProbability function randMod(uint _modulus) internal returns(uint) { randNonce++; @@ -214,7 +214,7 @@ material: } answer: > pragma solidity ^0.4.19; - + import "./zombiehelper.sol"; contract ZombieBattle is ZombieHelper { @@ -235,7 +235,7 @@ material: Зомби-битвы будут устроены так: -- Ты выбираешь одного из своих зомби-бойцов и подбираешь ему оппонента +- Ты выбираешь одного из своих зомби-бойцов и подбираешь ему оппонента - Если ты атакуешь, то у твоего зомби 70% шанс на победу. У защищающегося зомби шанс выиграть 30% - Все зомби (атакующие и защищающие) будут иметь `winCount` и `lossCount`, которые меняют значение в зависимости от результата боя - Если атакующий зомби побеждает, он получает следующий уровень и производит нового зомби diff --git a/ru/4/battle-04.md b/ru/4/battle-04.md index 35ad63e6dd..14dfddd681 100644 --- a/ru/4/battle-04.md +++ b/ru/4/battle-04.md @@ -44,9 +44,9 @@ material: return (_zombie.readyTime <= now); } - // 2. Add modifier to function definition: + // 2. Добавь модификатор к определению функции: function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal { - // 3. Remove this line + // 3. Удали эту строку require(msg.sender == zombieToOwner[_zombieId]); Zombie storage myZombie = zombies[_zombieId]; require(_isReady(myZombie)); diff --git a/ru/4/battle-06.md b/ru/4/battle-06.md index cac1b62777..aa0e1a4a6e 100644 --- a/ru/4/battle-06.md +++ b/ru/4/battle-06.md @@ -22,7 +22,7 @@ material: // 1. Здесь добавь модификатор function attack(uint _zombieId, uint _targetId) external { - // 2. Здесь определи функцию + // 2. Здесь определи функцию } } "zombiehelper.sol": | @@ -214,7 +214,7 @@ material: } answer: > pragma solidity ^0.4.19; - + import "./zombiehelper.sol"; contract ZombieBattle is ZombieHelper { diff --git a/ru/4/battle-08.md b/ru/4/battle-08.md index 129e4c1250..dd524bb45a 100644 --- a/ru/4/battle-08.md +++ b/ru/4/battle-08.md @@ -147,6 +147,8 @@ material: uint dna; uint32 level; uint32 readyTime; + uint16 winCount; + uint16 lossCount; } Zombie[] public zombies; @@ -155,7 +157,7 @@ material: mapping (address => uint) ownerZombieCount; function _createZombie(string _name, uint _dna) internal { - uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime))) - 1; + uint id = zombies.push(Zombie(_name, _dna, 1, uint32(now + cooldownTime), 0, 0)) - 1; zombieToOwner[id] = msg.sender; ownerZombieCount[msg.sender]++; NewZombie(id, _name, _dna); @@ -216,7 +218,7 @@ material: } answer: > pragma solidity ^0.4.19; - + import "./zombiehelper.sol"; contract ZombieBattle is ZombieHelper {