Глава 4. Программирование на Solidity

Содержание страницы

Глава 4

Solidity – это новый язык программирования, предназначенный для написания программ, называемых смарт-контрактами, которые могут запускаться виртуальной машиной Ethereum (EVM). Этот новый язык представляет собой совокупность соглашений из сетевых технологий, языка ассемблера и веб-разработки.

Представьте, что вы на пляже в другой стране. Вы приехали сюда неожиданно для себя и проскочили мимо пункта обмена валюты в аэропорту, полагая, что сможете использовать свою кредитную или дебетовую карту во время поездки и что у вас не будет потребности в наличных деньгах. В спешке вы забыли свои солнцезащитные очки. У продавца, идущего по пляжу, есть очки, которые вам подходят. По факту, они лучше, чем те очки, которые вы заметили в зоне duty-free в аэропорте. К несчастью, у него нет устройства для чтения кредитных карт – только телефон на Android – а у вас нет местной валюты. Он дает вам небольшую визитную карточку с адресом электронной почты и номером телефона, на случай, если вы захотите купить эти очки позже. На мгновение задумайтесь о подобном сценарии, и вы осознаете силу основанной на протоколе цифровой валюты.

Почему вы можете отправить человеку текстовое сообщение или e-mail, или даже позвонить ему, но не можете отправить ему деньги также просто?

Для начинающих

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

В общем смысле, вычислительная среда представляет собой бесконечный цикл, в котором раз за разом выполняется какая-либо текущая операция согласно программному счетчику. (Перемещение по очереди в программном счетчике производится при помощи операционного кода JUMP). Счетчик программы выполняет итерации одну за другой до тех пор, пока не будет достигнуто завершение конкретной программы. Машина выходит из цикла исполнения только в том случае, если она встречает (выдает) ошибку или получает инструкцию, в которой ей говорится остановиться (STOP) или вернуть (RETURN) результат или значение.

Эти операции имеют доступ к трем типам областей хранения данных:

  • Стек – контейнер, в который могут быть добавлены или удалены значения (push или pop). Значения стека определяются с помощью метода.
  • Динамическая память (реализуемая с помощью “heap” или “кучи”) – бесконечно расширяемый байтовый массив. Она сбрасывается, когда программа завершается.
  • Хранилище ключей/значений для балансов аккаунтов, в случае с адресами контрактов – код на Solidity.

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

Воплощение глобальной банковской системы (но это не точно)

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

Очень крупная инфраструктура

Система, такая как Ethereum, имеет узлы по всему миру, которыми управляют частные лица, они получают вознаграждение за свою деятельность в виде комиссий за майнинг, выраженных в эфире. Мы рассмотрим, как это работает, в Главе 6. Система очень децентрализована.

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

Общемировая валюта?

Как видите, идея об универсальной криптовалюте, похоже, основана на предположении, что каждый человек на Земле со временем загрузит криптовалютный кошелек на свой мобильный телефон. Однако, реализация подобной утопической мечты не предусмотрена дорожной картой Ethereum. Вместо этого разработчики ядра Ethereum решили упростить третьим сторонам создание дополнительных валют или кастомных токенов, которые будут выпускаться под их брендом и использоваться для особых целей (по аналогии с системой наград за использование кредитных карт).

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

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

Дополнительная валюта

Зачем вообще стране могут быть нужны несколько видов денег? В течение десятилетий, ведущих к становлению Федерального Резерва, сегодняшнего центрального банка США, в обороте было множество локальных валют. Эти бумажные банкноты, как правило, были обеспечены депонированным где-либо золотом и в силу этого были локальными по своей сути; сертификат на золото стоит мало, если учреждение, которое его выкупает, находится за тысячи километров. В период, предшествовавший широкому распространению систем частных денег (период в истории США, известный как эра “диких” банковских операций), многие типографии сделали своим основным источником дохода печатание денег с различными антиконтрафактными особенностями, чтобы конкурировать с другими типографиями.

Бенджамин Франклин был владельцем одной из таких типографий, которые обогащались за счет печатания дополнительных валют. В действительности, он был известен своими мерами по борьбе с подделками, выходящими за рамки общепринятых. По данным Смитсоновского института, однажды он официально выпустил местную валюту Пенсильвании с ошибкой в названии штата, в надежде ввести в заблуждение фальшивомонетчиков, которые считали, что эти банкноты были подделками. Многие из векселей, напечатанных Франклином, содержали слова “To Counterfeit is Death” (“Смерть за фальшивомонетничество”).

Понятие “дополнительная валюта” относится к средствам обращения, действующим наряду с национальной фиатной валютой, удовлетворяющим потребности, с которыми не может справиться национальная валюта. Эти валюты обычно имеют четыре цели:

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

Программирование на Solidity позволяет любому человеку создавать дополнительную валюту с простым контрактом токена. Эти токены могут обладать любыми параметрами, которые требуются исходя из ситуации, вы узнаете об этом, когда мы будем разворачивать контракт токена в Главе 5.

Перспективы Solidity

Solidity – это высокоуровневый контрактно-ориентированный язык, схожий с JavaScript и языками C. Он позволяет вам разрабатывать контракты и компилировать их в байт-код EVM. В настоящее время это флагманский язык для Ethereum. Хотя это и самая популярная библиотека языка для работы с EVM, она не была первой и, вероятно, не будет последней.

В протоколе Ethereum есть четыре языка на одинаковом уровне абстракции, но сообщество постепенно начало склоняться к Solidity, который потеснил Serpent (близкий к Python), LLL (Lisp-подобный язык) и Mutan (похожий на Go), последний из которых признан устаревшим.

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

Вы можете найти официальную документацию Solidity по адресу.

Однако, и другие сайты также предоставляют полезные материалы по Solidity. Для удобства, вся самая популярная документация по Solidity находится по ссылке.

Браузерный компилятор

Самый распространенный способ тестирования кода на Solidity – использование компилятора на базе браузера. Его можно найти по адресу.

Для быстрого ознакомления вы также найдете его на странице.

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

Изучение программирования EVM

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

Примечание

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

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

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

Примечание

Сервер – это компьютер, который действует согласно отведенной ему роли, выступая в качестве составной части определенного вида сервиса, который вы хотите предоставить людям через интернет. Некоторые сервера хранят данные (подумайте об электронных таблицах информации, таких как имена и адреса клиентов) в так называемых базах данных. Некоторые сервера запускают приложения, к которым другие компьютеры могут иметь доступ через сеть.

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

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

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

Простое развертывание

Не факт, что в Ethereum у вас будут возникать трудности с развертыванием и масштабированием обычного веб-приложения. Все необходимые смарт-контракты для бэкенда распределенного приложения, также известного как dapp, могут быть аккуратно упакованы в несколько документов и отправлены в EVM, и раз! – ваша программа становится доступной в этот же момент любому человеку на Земле, у которого установлен кошелек Ethereum или узел c командной строкой. Сегодня разработчики могут захотеть создать “гибридные” децентрализованные приложения Ethereum, которые будут доступны через обычные веб-браузеры, и в этом случае реализация возможности проведения платежей в эфире только прибавляет работы. Но к тому времени, когда работа над сетью будет завершена через 2-3 года, будет гораздо проще хостить все компоненты приложения с использованием протокола Ethereum.

Примечание

В бизнес-сленге время разработки и вывода на рынок (TTV) – это количество времени, которое проходит с момента, когда клиент запрашивает что-либо, до момента, когда он получает это. Это может быть чем-то осязаемым, материальным, а может и не быть. Однако низкое время TTV предполагает, что продукт или сервис можно легко продумать, а также быстро предоставить его людям, которые хотят его использовать.

В Ethereum можно быстро и недорого (хотя и не просто, пока еще) разрабатывать и разворачивать неизменяемые, работающие без сбоев, нецензурируемые приложения, которые перемещают реальные ценности на произвольные расстояния. И все это бесплатно, за исключением расходов на газ, генерируемых вашими программами, и расхода вашего личного времени (и времени работы вашего компьютера). Для инженеров программного обеспечения, поставщиков услуг, системных администраторов и менеджеров по продуктам долгосрочным последствием работы с экосистемой Ethereum будет появление менее хрупких систем, более быстрый выпуск итераций продукта и гораздо меньшее время на развитие инфраструктуры для поддержки новых приложений или сервисов. Короче говоря, это может привести к существенному сокращению времени TTV для вендоров корпоративного программного обеспечения и групп штатных специалистов.

Кейс по написанию бизнес-логики на Solidity

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

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

Дополнительная валюта также является очень ценным инструментом для использования в программах вознаграждений, клубах по интересам и крупных розничных территориях. Клиенты, которые держат деньги в форме брендированной монеты, склонны тратить на этот бренд более регулярно, также как постоянные авиапассажиры сегодня остаются лояльными “милям в воздухе” и схемам бонусов по кредитным картам, которые предоставляют им лучшую выгоду.

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

Пиши, внедряй, расслабляйся

Многие приложения, поддерживающие Ethereum, могут использоваться через кошелек Mist или другое Ethereum-нативное приложение, у которого “под капотом” запущена нода. Для разработчиков клиентских приложений добавление совместимости с новыми токенами на основе Ethereum тривиально, в том плане, что будет существовать высокий уровень наложения и взаимосовместимости между кошельками Ethereum и токенами, так же как сегодня существует множество IMAP- и POP-совместимых email-клиентов.

Также сегодня имеется возможность создания Ethereum-программы, которая будет доступна через обычный старый Веб, для чего потребуется определенная доработка. Впрочем, развертывание будет становиться все более легким с использованием новых сторонних фреймворков, примеры которых приведены в Главе 8.

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

Обоснование архитектуры

Язык программирования Solidity имеет JavaScript-подобный синтаксис, но он был специально разработан для компиляции в байт-код для виртуальной машины Ethereum. Как было отмечено в Главе 3, EVM запускает код, который полностью детерминирован; одинаковые алгоритмы с одинаковыми входными данными всегда будут давать одинаковые результаты. Это можно доказать математически, как вы узнаете позже в этой главе.

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

Примечание

Понятие “типы данных” говорит само за себя. Программист имеет возможность сообщить машине, какой тип данных ожидать: для примера, будет ли это число или строка из букв? Языки программирования со слабой типизацией не требуют от программиста быть конкретным; языки со строгой типизацией требуют.

Интересно, что в Solidity вы можете писать ассемблерные вставки. Если вы предпочитаете выполнять определенную операцию, используя один из операционных кодов EVM, перечисленных в Главе 3, вы можете встраивать этот код в свои контракты на Solidity. Просто напишите assembly {…} в своем коде вместо инструкции на Solidity.

Написание циклов в Solidity

Циклы служат основой для потока управления в программировании – другими словами, речь о кодификации if-this-then-that (если это, тогда то) ситуаций или do-this-while-doing-that (делать это, пока делается то) параллелизмов. В большинстве языков программирования циклы инициализируются одинаковым синтаксисом. Solidity придерживается всех тех же синтаксических принципов, что и JavaScript, и C+, когда дело касается циклов.

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

Цикл общего назначения имеет схожий синтаксис в JavaScript, C и Solidity. Он инструктирует компьютер сосчитать от 0 до 10:

for (i=0; i<10; i++) {…}

Если вы внимательно изучили список операционных кодов в предыдущей главе, вы, возможно, заметили, что EVM позволяет создавать циклы двумя способами. Вы можете писать циклы на Solidity или создавать их с помощью инструкций JUMP и JUMPI. Это обеспечивает переход к определенному номеру шага в программном счетчике. Вспомним, что счетчик программы отслеживает количество и порядок вычислительных шагов в заданной программе в процессе ее выполнения в EVM.

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

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

Выразительность и безопасность

Прилагательное “выразительный” используется в науке о вычислениях для обозначения кода, который легко написать и понять человеку. Выразительные языки – это мост между мыслительными паттернами человека и паттернами исполнения машины. Быть выразительным для языка значит, что его различные конструкции должны быть интуитивно понятными, а его шаблонный код (в частности, ключевые слова, специальные переменные и операционные коды) должен использовать удобные для восприятия человеком слова, которые помогут программистам помнить, что они собой представляют.

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

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

Важность формальных доказательств

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

Это далеко не узкоспециализированный спор, это самый актуальный вопрос, связанный с ролью инженеров программного обеспечения в современном мире: может ли человечество создать свободный, открытый для доступа виртуальный компьютер, который другие люди не смогут саботировать? Если ответ будет “да”, то он резко противоречит теории трагедии ресурсов общего пользования.

Историческое влияние общего глобального ресурса

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

Вот пример: в Нью-Йорке в конце 2016-го года муниципальное правительство установило компьютерные терминалы на улицы Нижнего Манхэттена. Эти терминалы предоставляли бесплатный Wi-Fi для проходящих пешеходов. Однако, эти терминалы также поставлялись с небольшим сенсорным экраном, позволяющим пользоваться доступом в интернет. Стоило только установить эти общие ресурсы, как проходящие мимо люди начали ставить стулья, смотреть YouTube или порнографию, ковыряться в сети часами.

Администраторы программы были вынуждены быстро ограничить доступ к интернету через экран, и теперь терминалы служат в основном как обычные точки доступа Wi-Fi.

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

Как злоумышленники разрушают сообщества

Децентрализованные экономики представляют собой зарождающуюся угрозу всем видам частных привилегированных кругов по всему миру, особенно в развивающихся экономиках, где могущественные люди предпочли бы, чтобы мир продолжил свое существование без решения трагедии ресурсов общего пользования (и таким образом, у власти бы оставались новые диктаторы или сборище безумцев). Безопасность сети Ethereum является предметом Главы 7. Однако средства защиты Ethereum находятся повсюду, даже непосредственно в языке программирования, поэтому следует упомянуть о них.

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

Гипотетическая атака, написанная на Solidity

Представьте, что атакующий хочет заблокировать EVM с помощью смарт-контракта, написанного на Solidity, который будет потреблять крайне много памяти. Злоумышленник готов заплатить за газ, сколько бы он ни стоил. (Это реальный сценарий, как вы узнаете из Главы 7). Имейте ввиду, что для целей из этого примера контракт также может быть написан на любом языке, созданном для EVM, например, на Serpent или даже на низкоуровневом EVM-коде, а не только на Solidity.

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

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

Примечание

Смарт-контракты отличаются от распределенных приложений (или dapps), хотя и те, и другие распределены и обладают свойствами приложений. Dapp – это приложение с графическим пользовательским интерфейсом, которое использует смарт-контракты Ethereum на бэкенде, а не обычную базу данных и хостинг-провайдера для веб-приложений. Доступ к dapps можно получить через браузер Mist или через интернет.

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

Хотя серые области нельзя было проработать изначально, их можно исправить серией форков протокола со временем. Что касается непреднамеренно разрушительных программ, то задача сообщества Ethereum – разрабатывать шаблоны и методы, которые будут способствовать идейно простым, легко доказуемым контрактам, которые могут разрабатываться по стандартным шаблонам. В Главе 5 рассматриваются некоторые из этих лучших практик.

Автоматические доказательства идут на помощь?

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

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

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

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

Детерминизм на практике

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

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

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

Потери при преобразовании

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

Процесс компиляции – перевод понятного человеку кода в низкоуровневый, машинный код – приносит в жертву много (интерпретируемой человеком) информации о том, как рассуждать о программе. Он также  жертвует информацией, которая была бы полезной для автоматического доказательства теорем. Таким образом, в процесс всегда вводится некоторая неопределенность или неоднозначность. Сегодня вы не можете быть полностью уверены, что даже математически доказанный смарт-контракт, написанный на Solidity, будет по-прежнему оставаться доказуемым после компиляции.

Тестирование, тестирование, тестирование

Способ предотвратить потерю ваших денег из-за неоднозначности кода – это протестировать его вдоль и поперек. Сеть Ethereum поставляется с тестовой сетью Ropsten, которая использует тестовый эфир, который ничего не стоит и может быть быстро получен из крана в среде-”песочнице”.

На самом деле Ropsten ничем не отличается от основной цепочки. Это просто другая цепочка, предназначенная для тестирования. Подобно “Титанику” и кораблю аналогичного класса “Британнику”, они идентичны, за исключением имен, как и любая другая цепочка, запущенная кем-либо. В этих цепочках нет ничего особенного или священного; вы создадите цепочки, подобные им, в Главе 8.

Командная строка

Имейте в виду, что большинство важных функций Ethereum можно выполнить в кошельке Mist: отправить и получить эфир, отследить токены и развернуть контракты. Использование Geth (или другого клиента командной строки) является хорошим выбором для разработчиков, которые собираются научиться писать dapps. Глава 6 уделяет больше внимания Geth.

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

Примечание

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

Вы узнаете, как развернуть такой контракт в Главе 5. Вы будете рады узнать, что существует всего три требования для развертывания простого контракта на Solidity:

  • Текстовый редактор, такой как TextEdit на MacOS, Gedit на Ubuntu или Notepad на Windows. Убедитесь, что включен режим текста без форматирования, который уберет все шрифты, подчеркивания, выделения жирным, гиперссылки и курсивный шрифт. (Никогда не используйте жирный шрифт для написания кода!)
  • Кошелек Mist, рассмотренный в Главе 2.
  • Браузерный компилятор Solidity, расположенный по адресу или доступный по следующей короткой ссылке.

Как мы продемонстрируем в Главе 5, все, что вам нужно сделать, чтобы “загрузить” контракт, это скопировать и вставить ваш код на Solidity из текстового редактора в браузерный компилятор Solidity. Оттуда вы будете компилировать код в байт-код и копировать-вставлять этот байт-код в Mist. Это действительно очень легко, но давайте не будет увязать в логистике сейчас. Вместо этого мы рассмотрим поведение смарт-контракта ниже, так чтобы вы смогли осознать потенциал автоматического контракта, который отправляет и получает деньги. Следующий пример был изначально написан Сайрусом Эдкиссоном (fivedogit на GitHub), инженером программного обеспечения из Кентукки и энтузиастом Ethereum, проживающим сейчас в Нью-Йорке. Он был адаптирован для этой книги.

Вы назовете этот контракт PiggyBank (“копилка”), используя CapsCase (вместо camelCase) согласно правилам именования в Solidity. Вы можете найти эти правила именования и остальную часть руководства по стилю Solidity по ссылке.

Теперь давайте посмотрим на PiggyBank.sol:

contract PiggyBank { address creator; uint deposits;

//Объявление этой функции как публичной делает ее доступной для других пользователей и смарт-контрактов.

function PiggyBank() public

{

creator = msg.sender; deposits = 0;

}

//Проверяется, было ли помещено какое-либо количество эфира на депозит. Когда он депонирован, количество депозитов увеличивается   и общее количество возвращается.

function deposit() payable returns (uint)

{

if(msg.value > 0) deposits = deposits + 1;

return getNumberOfDeposits();

}

function getNumberOfDeposits() constant returns (uint)

{

return deposits;

}

//Когда внешний аккаунт, который создал этот контракт, снова вызывает его, он завершает работу и отправляет обратно  свой  баланс.

function kill()

{

if (msg.sender == creator) selfdestruct(creator);

}

}

Вы можете найти больше примеров скриптов на Solidity для программистов всех уровней и навыков по адресу.

Форматирование Solidity-файлов

Одна из основных деталей отсутствует в предыдущем примере контракта. Каждый файл Solidity должен иметь (но не обязательно) версию препроцессорной директивы (pragma), указание версии Solidity, на которой был написан контракт. Со временем это должно предотвращать ситуации, когда будущие версии компилятора отказываются принимать старые контракты.

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

pragma solidity ^0.4.7;

Дополнительные сведения о структуре файлов Solidity можно найти по адресу.

Советы по чтению кода

Вот шесть фактов, которые сделают этот контракт более понятным для начинающих:

  • Компьютеры читают код сверху вниз, слева направо, как и носители английского языка. Размещение одной строки перед другой в общем случае означает, что компьютер сначала увидит эту инструкцию.
  • Как правило, программы берут входные данные и возвращают выходные данные. Вычислимые функции (математические функции, которые могут выполняться компьютером) определяются как функции, которые могут быть записаны как алгоритмы.
  • Алгоритмы получают данные, выполняют по ним операцию и возвращают какие-либо выходные данные. Программы – это алгоритмы с другими вложенными в них алгоритмами.
  • Алгоритм подобен машине: вы можете многократно использовать его. Таким образом, написание алгоритмических инструкций – программирование – покажется вам очень похожим на игру Mad Libs, которую компьютер впоследствии автоматически заполняет пользовательской информацией (или контрактом Ethereum) посредством транзакции или вызова сообщения. Иногда эта информация представляет собой простое число (например, 5 эфиров).
  • Операторы – это символы между английскими словами, такие как знак равенства, знаки плюса и минуса. Они работают по большей части так, как вы и ожидаете, за некоторыми исключениями. Вы увидите операторы Solidity в таблице 4-1.

Таблица 4-1.

Приоритет Описание Операция
1 Постфиксный инкремент декремент  

и

++, —
Вызов как функции <func> (<arg…>)
Индексация массива <array>[<index>]
Доступ к элементу <object>.<member>
Круглые скобки (<statement>)
2 Префиксный инкремент декремент  

и

++, —
Унарный минус плюс и +, –
Унарные операции delete
Логическое NOT !
Побитовое NOT
3 Возведение в степень **
4 Умножение,    деление и остаток от деления *, /, %
5 Прибавление вычитание и +, –
6 Побитовый    оператор смещения <<, >>
7 Побитовый AND &
8 Побитовый XOR ^
9 Побитовый OR |

 

10 Операторы сравнения <, >, <=, >=
11 Оператор                      равенcтва, оператор неравенства ==, !=
12 Логическое AND &&
13 Логическое OR ||
14 Тернарный оператор <corditional>                                      ?

<if-true>    :      <if-false>

15 Оператор присвоения =, |=, ^=, &=, <<=, >>=,

+=, -=, *=, /=, %=

16 Оператор “запятая” ,

 

  • Типы – это “существительные” компьютерного программирования. Поэтому когда вы видите тип, вы знаете, что разрешено в этом пространстве Mad Lib. Общий тип в Solidity – это адрес.

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

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

Компьютер самостоятельно определит, сколько памяти выделить для хранения значений в любых временных или так называемых динамических вычислениях – небольших, ключевых логических операторах, используемых для вычисления условных операций, таких как if-then (если-то). (Важно определить стек и heap (“кучу”), чтобы убедиться в том, что именно здесь находится опасность программ, пожирающих память: в указании компьютеру использовать больше динамической памяти, чем он может выделить).

Операторы и выражения в Solidity

Как вы узнаете, функции присутствуют в Solidity повсюду. Однако они используются по-разному.

Некоторые функции дают на выходе значение, например, число или ответ на вопрос true/false. Каким именно может быть это значение, определяется типами Solidity, о которых упоминалось ранее; значение true/false называется Boolean.

Что такое выражение?

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

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

Что такое оператор?

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

Публичные и приватные функции

В JavaScript и Solidity вы можете использовать точки с запятой для связывания операторов в цепочку и сообщать компьютеру, что в коде появляется другой оператор:

function first(); function second()

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

  • public (публичная): видимая извне и изнутри (создается функция доступа для переменных хранения/состояния)
  • private (приватная): видимая только в текущем контракте (по умолчанию)

Примечание

Функции, написанные на Solidity, по умолчанию не являются публичными. Вы должны объявить их публичными при создании, или они не будут доступны для контрактов за пределами того контракта, в котором они находятся. (Прим. переводчика: на момент перевода книги тип видимости функций по умолчанию – public)

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

Типы значений

При написании кода на Solidity вы можете указать компьютеру, какой тип значений ожидать в каждой алгоритмической инструкции. В этом разделе описываются типы значений, который EVM может интерпретировать.

Логические значения

Известные в программировании как bool, логические (булевы) выражения

  • это выражения true/false, результатом вычисления которых является “истина” или “ложь”.

Целые числа со знаком и без

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

Адреса

Тип адреса содержит 20-байтовое значение, которое представляет собой размер адреса Ethereum (40 шестнадцатеричных символов или 160 бит). Типы адресов также имеют типы методов.

Методы адресов

Эти два метода позволяют вам запрашивать баланс аккаунта или переводить эфир на аккаунт. Будьте внимательны с методом transfer в смарт-контрактах. Лучше использовать паттерн, в котором получателю позволено снимать деньги, чем иметь контракт, инициирующий переводы.

  • balance
  • transfer

Ключевые слова, связанные с адресом

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

  • .balance (uint256): возвращает баланс адреса в wei
  • .send(uint256 сумма) returns  (bool): отправляет заданную сумму в wei на адрес и возвращает false при неудаче
  • this(тип текущего   контракта):  текущий      контракт,      явно преобразуемый в address
  • selfdestruct(адрес получателя): уничтожает текущий контракт, отправляет его средства на заданный адрес

Примечание

Возможно запросить баланс текущего контракта, используя ключевое слово this.balance.

Менее общие типы значений

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

  • Байтовые массивы с динамическим размером
  • Числа с фиксированной запятой
  • Рациональные и целочисленные литералы
  • Строковые литералы
  • Шестнадцатеричные литералы
  • Перечисления

Комплексные (ссылочные) типы

В целом, типам в Solidity выделяется 256 бит памяти в хранилище EVM; это 2048 символов. Более длинные типы могут привести к более значительным затратам на газ для перемещения. Вам нужно тщательно выбирать типы во время выделения постоянного хранилища в стеке EVM. Вот комплексные типы, которые превышают 256 бит:

  • Массивы
  • Литералы массивов / строковые массивы
  • Структуры
  • Соответствия

Массивы, структуры и другие комплексные типы имеют расположение данных, которое может использоваться программистами на Solidity для управления вне зависимости от того, как они хранятся, динамически в памяти или в среде постоянного хранения. Это может помочь вам управлять комиссиями.

Глобальные специальные переменные, единицы и функции

Глобальные специальные переменные могут быть вызваны любым смарт-контрактом на Solidity в EVM; они встроены в язык. Большинство из них возвращают информацию о цепочке Ethereum. Единицы времени и эфира также глобально доступны. Литеральные числа могут принимать суффиксы wei, finney, szabo или ether и будут автоматически конвертироваться между субноминалами эфира. Числа валюты эфира без суффикса считаются Wei.

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

Ввиду существования високосных годов будьте осторожны при использовании этих суффиксов для расчета времени, поскольку не все годы имеют 365 дней, и не все сутки имеют 24 часа. 1000 миллисекунд = 1 секунда, 1 минута = 60 секунд, 1 час = 60 минут, 1 день = 24 часа, 1 неделя = 7 дней, 1 год = 365 дней.

Свойства блока и транзакции

Обратите внимание, что эти глобальные переменные доступны только в смарт-контрактах на Solidity. Их не следует путать с вызовами JavaScript Dapp API, которые вы можете делать в Geth, о которых вы узнаете в Главе 6.

  • block.blockhash (uint blockNumber) returns (bytes32): Хеш данного блока, работает только для 256 последних блоков
  • block.coinbase (address): Адрес майнера текущего блока
  • block.difficulty (uint): Текущая сложность блока
  • block.gaslimit (uint): Текущее ограничение блока по газу
  • block.number (uint): Номер текущего блока
  • block.timestamp (uint): Временная метка текущего блока
  • msg.data (bytes): Полные данные вызова
  • gas (uint): Оставшийся газ
  • msg.sender (address): Отправитель сообщения (текущий вызов)
  • msg.sig (bytes4): Первые 4 байта данных вызова (идентификатор функции)
  • msg.value (uint): Количество отправленных Wei с сообщением
  • now (uint):  Временная     метка     текущего     блока     (алиас     для

block.timestamp)

  • tx.gasprice (uint): Цена газа транзакции
  • tx.origin (address): Отправитель  транзакции (полная цепочка вызова)

Обратите внимание, что значения всех методов msg (то есть, msg.sender и msg.value) могут изменяться для каждого вызова внешней функции, даже если они являются библиотечными функциями. Если вы хотите реализовать библиотечные функции с ограничениями доступа на использование msg.sender, вам необходимо вручную указать значение msg.sender в виде аргумента.

Памятка по операторам

В таблице 4-1 показаны операторы, которые вы можете использовать в выражениях на Solidity.

Глобальные функции

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

  • keccak256(…) returns    (bytes32):   Вычисляет        хеш Ethereum-SHA-3 (Keccak-256) аргументов (плотно упакованных)
  • sha3(…) returns (bytes32): Алиас для keccak256()
  • sha256(…) returns (bytes32): Вычисляет хеш SHA-256 (плотно упакованных) аргументов.     “Плотно     упакованный”     означает,      что аргументы   связаны/соединены   без    заполнения.   Чтобы    узнать,   как добавить заполнение к аргументам, обратитесь к следующей ссылке.
  • ripemd160(…) returns (bytes20): Вычисляет RIPEMD-160 хеш (плотно упакованных) аргументов
  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address): Восстанавливает адрес, связанный с открытым ключом из подписи эллиптической кривой, возвращает 0 при ошибке
  • addmod(uint x, uint y, uint k) returns (uint): Вычисляет (x + y) % k, где суммирование происходит с произвольной точностью и не повторяется при 2**256
  • mulmod(uint x, uint y, uint k) returns (uint): Вычисляет (x* y) % k, где умножение происходит с произвольной точностью и не повторяется при 2**256
  • this (текущий тип контракта): Текущий контракт, явно преобразуемый в его адрес. Также стоит упомянуть переменные, связанные с контрактами, которые могут быть полезны при написании контрактов на Solidity:
  • super: Контракт на один уровень выше в иерархии наследования. Для получения дополнительной информации о наследовании, смотрите ссылку в следующем разделе
  • selfdestruct(адрес получателя): Уничтожает текущий контракт, отправляет его средства на указанный адрес
  • assert(bool condition): отдает исключение, если условие не выполняется
  • revert(): Прекратить выполнение и откатить изменения состояния

Исключения и наследование

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

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

Итоги Главы 4

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

Мы лишь кратко коснулись формальной математики, которая делает эти программы столь многообещающими для корпоративных информационных технологий. Но, если повезло, вы узнали достаточно для мотивации углубиться в Ethereum White Paper и Yellow Paper и увидеть своими глазами, как EVM достигает доказуемого консенсуса.

В Главе 5 вы развернете свой первый токен-контракт в EVM. Вы также узнаете о социальной и культурной истории монетарных инструментов, а также какую роль это играет для вашего понимания потенциала Ethereum.

Примечания к Главе 4

  1. Smithsonian Education, “Revolutionary Money,” http://www.smithsonianeducation.org/educators/lesson_plans/revolutionary_money/i ntroduction.html, 2016.
  2. Wikipedia, “Counterfeit  Money,” https://en.wikipedia.org/wiki/Counterfeit_money, 2016.
  3. Investopedia, “Complementary Currency,” www.investopedia.com/articles/economics/11/introduction-complementary-currencie s.asp, 2016.
  4. New York Times, “Internet Browsers to Be Disabled on New York’s Free Wi-Fi Kiosks,” www.nytimes.com/2016/09/15/nyregion/internet-browsers-to-be-disabled-on-new-yor ks-free-wi-fi-kiosks.html?_r=0, 2016.
  5. Wikipedia, “Rice’s Theorem,” https://en.wikipedia.org/wiki/Rice%27s_theorem, 2016.

Понравилась статья? Поделить с друзьями:
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: