Вы здесь

Приключения с тупыми контрактами

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

Приключения с тупыми контрактами

Приключениум

Вместо того, чтобы погружаться непосредственно в описание какого-нибудь «сочного» кода или абстрактных концепций дизайна, я познакомлю вас с даппом, из-за которого сегодня весь сыр-бор. Это прикольная незамысловатая игра, которую я называю Приключениум: гибрид от Приключения и Эфириума, а поскольку это крипта, подобные криповатые названия вполне сгодятся.

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

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

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

Использование газа и хранение данных

Каждый, у кого есть хоть какой-то маломальский опыт разработки для Эфириума, хорошо знает о самых дорогих (на сегодняшний день!) операциях на виртуальной машине Эфириума (EVM) – внесение записей в хранилище. Чем больше данных вы записываете, тем дороже выходит хранение, поэтому если я попрошу своих пользователей записывать большие куски текстов для текстовой игры, это может обернуться проблемой. А мы не хотим наказывать своих пользователей за их энтузиазм или креативность.

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

Текст для игроков, а мы имеем дело с кодом.

И какие у нас есть обходные пути? Мы могли бы поколдовать с межпланетной файловой системой (IPFS), сохранив ссылку на хэш IPFS, и сделать все это в самом начале, но это могло несколько усложнить процесс и вызвать больше сложностей в начале пути, который наоборот должен проходить гладко. Что-то может пойти не так с IPFS, плюс ко всему это решение в целом не настолько «изящное», как должно быть. Более подходящим решением являются....

Тупые контракты

Тупые контракты! Я буду честен, можно было бы найти другое название, о котором я не знаю, но я один раз услышал его, и мне оно понравилось. Тупой контракт – это шаблон умного контракта, который извлекает выгоду из Событий и пользуется их относительной дешевизной по сравнению с внесением записей в хранилище. Для записей в хранилище требуется гораздо больше газа, чем для выпуска неиндексируемых параметров событий, и поскольку журналы событий полностью и легко доступны, он кажется идеальным местом для хранения текста игры.

Приведите мне пример

Вместо того, чтобы абстрактно говорить об этом, давайте приведем пример. Предположим, вы хотели сохранить «Гамлета» Шекспира в блокчейне Эфириума с индексацией по абзацам. Честно говоря, я понятия не имею, почему вы хотите это сделать, но давайте продолжим.

Используя традиционные методы хранения для умных контрактов, вы, вероятно, получите что-то типа этого:

        contract Hamlet_store{
string[] public paragraphs;
function writeText(string memory paragraphText) public {
    paragraphs.push(paragraphText);
}
}

Когда абзац записан, вы сохраняете его в массиве данных, а затем просто читаете из этого массива, когда хотите восстановить абзац. Если вы хотите сделать более сложные вещи в своем умном контракте с номерами страниц, вы всегда будете ссылаться на этот индекс массива и читать из массива.

Если мы используем часть разговора между Гамлетом и Горацио, абзац, который начинается с «Как к чудесам, вы к ним и отнеситесь» и заканчивается словами «В чем Вседержитель милостью своей Вам да поможет в трудный час. Клянитесь.», и записываем его с использованием вышеприведенной функции, выполнение транзакции обойдется в 551896 газа.

А теперь сравните это с шаблоном нашего тупого контракта, который будет выглядеть что-то типа этого:

        contract Hamlet_event{
event Paragraph(uint indexed num, string paragraphText);
uint paragraphs;
function writeParagraph(string memory paragraphText) public{
    emit Paragraph(paragraphs,paragraphText);
    paragraphs++;
}
}

Единственное, что хранится в умном контракте – это индекс абзаца, сам текст «отпочковывается» и попадает в журнал. За счет представления одного и того же абзаца в прежнем виде стоимость в конечном итоге составит для нас всего 99182 газа.

Но что важно: текст, который вы храните, легкодоступен с самого начала, независимо от того, какой метод вы используете. Поэтому если вы выбираете обычный метод, ваши пользователи платят 80% за это без всякой на то причины.

Предстоящее обновление Константинополя для Эфириума должно было иметь некоторые изменения в стоимости хранения, поэтому это может немного повлиять на цифры. Но цитируя Гамлета еще раз:

«Есть много в небесах и на земле такого,
Что нашей мудрости, Гораций, и не снилось».

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

Возвращение к игре

В любом случае, в конце, как большинство из вас уже догадались, я использовал этот образец тупого контракта, чтобы сохранить игровые ситуации в журнале Событий. В умном контракте есть логика, которая отслеживает, какой выбор к какой ситуации приводит, но на этом все. Еще одна вещь, о которой вы должны знать при использовании тупых контрактов, заключается в том, что есть только определенные типы переменных, которые могут быть созданы в событиях. Один тип, который не допускается, это динамический массив строк string[] like_this. У нас могут быть регулярные старые строки, но мы можем вставлять их в динамический массив, и тогда не будет никаких событий в этот вечер.

Фишка моего игрового дизайна заключается в том, что игрок, создающий часть истории, может устанавливать любое количество вариантов, которые вытекают из той или иной ситуации. Поэтому сохранение основного текста ситуации не является проблемой, но нам нужен способ для получения динамического массива строк. Есть несколько «хакерских» способов обмана массива, например, через выпуск события, но один способ, который мне нравится больше всего, это использование динамического массива bytes32.

Мы можем генерировать события с bytes32[] в качестве параметра, и для большинства разработчиков преобразование между строкой и байтами (string и bytes), скорее всего, не «взорвет» мозг его обладателю. Так что все, что мы должны сделать, это преобразовать выбор нашего игрока в байты перед его отправкой в сеть, а потом обратно преобразовать его в текст для нормальных людей, когда это нужно для игры.

Поскольку мы говорим о самом начале процесса, у Web3.js есть два способа сделать это: web3.utils.fromAscii для перевода строк в байты, а web3.utils.toAscii для преобразования их в обратное состояние.

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

Оговорка в отношении bytes32

Небольшая оговорка относительно метода bytes32 заключается в том, что он ограничивает длину каждого из вариантов, т.е. он не может быть больше 32 символов. Для моего игрового дизайна это нормально, т.к. я не хочу, чтобы игроки вставляли целые эссе в свой выбор.

Но если bytes32 не подойдет вам, помните, что прежде чем данные войдут в умный контракт или по их прочтении, вы можете сделать все, что хотите с ними. Возвращаясь к нашему примеру с Гамлетом, мы могли бы автоматически перевести весь текст на испанский язык, прежде чем сохранить его, а затем конвертировать его обратно в английский по прочтении из хранилища. Предполагая, что перевод был на самом деле правильным, у пользователя не было бы никакого способа это выяснить.

Так что вы можете разбивать более крупные строки на более мелкие, а затем преобразовать их в bytes32, или вы можете собрать их всех вместе в одну большую мега-строку, затем разбить их снова по прочтении... речь даже не о том, какое именно решение, а о том, что оно в принципе есть.

Игра продолжается

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

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

До встречи.

Категория: 
Криптовалюты
Технология: 
5
Ваша оценка: Нет Средняя: 5 (1 оценка)
10440 / 0
Аватар пользователя Serg Demin
Публикацию добавил: Serg Demin
Дата публикации: пн, 04/29/2019 - 10:18

Что еще почитать: