Я хочу поблагодарить коллег: Сергея Немеша, Михаила Попсуева, Евгения Бабича и Игоря Титаренко за консультации, отзывы и тестирование. Я также хочу сказать спасибо команде PolySwarm за разработку оригинальной версии Perigord.

Это перевод моей статьи, опубликованной впервые на английском на Medium Тестирование всегда было неотъемлемой частью разработки программного обеспечения, хотя и не самой приятной. Когда речь идет о смарт-контрактах, необходимо тщательное тестирование с исключительным вниманием к деталям, т.к. ошибки будет невозможно исправить после развертывания в блокчейн сети. За последние годы, сообщество Ethereum создало множество инструментов для разработки смарт-контрактов. Некоторые из них не стали популярными, например, Vyper — диалект Python для написания смарт-контрактов. Другие, такие как Solidity, стали признанным стандартом. Наиболее обширную документацию по тестированию смарт-контрактов на сегодняшний день предоставляет связка Truffle&Ganache. Оба этих инструмента имеют хорошую документацию, многие кейсы уже решались на Stack Overflow и подобных ресурсах. Однако, у этого подхода есть один важный недостаток: для написания тестов нужно использовать Node.js. Даже если вы не поклонник языков программирования со статической типизацией и любите JavaScript, подумайте о том, что можно сделать опечатку и начать сравнивать результат выполнения функции, которая возвращает строку с булевым значением, используя устаревший метод equal вместо strictEqual. Если checkProposal возвращает строки “yes” или “no”, вы всегда преобразуете их в true. Динамическая типизация скрывает множество таких ловушек, и даже опытные программисты могут совершать подобные промахи, работая на большом проекте или в команде с другими разработчиками, которые могут вносить изменения в код и не сообщать об этом.  Статическая типизация в Go позволяет предотвратить подобные ошибки. Кроме того, использование языка Go вместо Node.js для тестирования — мечта любого Go-разработчика, начинающего работу со смарт-контрактами. Моя команда занималась разработкой инвестиционной системы на основе смарт-контрактов с очень сложной архитектурой. Система смарт-контрактов содержала более 2000 строк кода. Поскольку основную часть команды составляли Go-разработчики, тестирование на Go было предпочтительнее, чем на Node.js. В 2017 PolySwarm разработали Perigord — инструмент схожий с Truffle, использующий Go вместо JavaScript. К сожалению, этот проект больше не поддерживается, у него есть всего один туториал с очень простыми примерами. К тому же, он не поддерживает интеграцию с Ganache (приватный блокчейн для разработки Ethereum с очень удобным GUI). Мы улучшили Perigord путем устранения багов и внедрения двух новых функций: генерации кошельков из мнемонического кода и их использования для тестирования и подключения к блокчейну Ganache. Вы можете ознакомиться с исходным кодом по ссылке.  Оригинальный туториал Perigord содержит только простейший пример вызова контракта для изменения одного значения. Однако в реальном мире вам также нужно будет вызывать контракт с разных кошельков, отправлять и получать Ether и т.д. Теперь вы можете делать все это, используя усовершенствованный Perigord и старый добрый Ganache. Ниже вы найдете подробное руководство по разработке и тестированию смарт-контрактов с помощью Perigord&Ganache. Для использования Perigord вам нужно установить Go 1.7+, solc, abigen и Ganache. Пожалуйста, ознакомьтесь с документацией для вашей операционной системы.  Установите Perigord следующим образом: После этого вы сможете использовать команду perigord:  Сейчас мы создадим простой смарт-контракт Market, чтобы продемонстрировать доступные варианты тестирования. Чтобы начать проект, введите в терминал следующее: Проект появится в папке src/ в GOPATH. Переместите проект в другую папку и обновите пути импортирования, если хотите изменить его расположение. Посмотрим, что находится в папке market/. Очень похоже на проект созданный в Truffle, не правда ли? Но это все на Go! Посмотрим, что в файле конфигурации perigord.yaml. Для тестирования вы можете использовать как приватную сеть geth и файлы кошельков, так и подключиться к Ganache. Эти варианты взаимоисключающие. Мы возьмем мнемонику, которая используется по умолчанию, сгенерируем 10 аккаунтов и подключимся к Ganache. Замените код в perigord.yaml на:  HTTP://127.0.0.1:7545 — стандартный адрес сервера Ganache RPC. Обратите внимание, что вы можете создать сколько угодно аккаунтов для тестирования, но только аккаунты, сгенерированные в Ganache (GUI), будут содержать средства.  Мы создадим контракт под названием Market.sol. Он может хранить запись пар адресов, один из которых отправляет средства на счет контракта, а другой имеет право получать средства, когда владелец контракта дает разрешение на такую транзакцию. Например, два участника не доверяют друг другу, но доверяют владельцу контракта, который решает, выполнено ли определенное условие. В примере реализовано несколько основных функций в целях демонстрации.  Добавим контакт в проект: Постфикс .sol будет добавлен автоматически. Вы также можете добавить другие контракты или удалить контракт-пример Foo.sol. Пока вы работаете в GOPATH, вы можете использовать импорт контрактов для создания сложных конструкций. У нас будет три файла Solidity: основной контракт Market, вспомогательные контракты Ownable и Migrations и библиотека SafeMath. Вы можете найти исходный код здесь. Теперь проект имеет следующую структуру: Генерируем байт-код EVM, биндинги ABI и Go: Добавляем миграции всех контрактов, которые вы будете деплоить. Т.к. мы деплоим только Market.sol, нам понадобиться всего одна новая миграция: Наш контракт не содержит конструктор, принимающий параметры. Если вам нужно передать параметры в конструктор, добавьте их в функцию Deploy{NewContract} в файле миграций: Удалите файл-пример Foo.go и добавьте тестовый файл для нашего контракта:  Чтобы использовать детерминированные кошельки, нам нужно прочитать мнемонику из файла конфигурации: Следующая вспомогательная функция используется для получения адреса сети: Еще одна вспомогательная функция, которая нам понадобится, — sendETH, мы будем использовать ее для передачи Ether с одного из сгенерированных кошельков (обозначенный индексом) на любой Ethereum адрес: Следующие две функции используются для изменения вызова контракта: Для вызова мы создаем contractSessionActual для определенного контракта. Т.к. у контракта есть владелец, мы можем получить его адрес и проверить, соответствует ли он дефолтному нулевому аккаунту Ganache. Мы сделаем это следующим образом (опустим обработку ошибок, чтобы сэкономить место): Следующая полезная функция — изменение кошелька, вызывающего контракт: Т.к. одна из основных функций, используемых в тестировании, — изменение вызывающего контракт, давайте сделаем платеж от имени отправителя: Полный код тестов приведен здесь. Теперь откроем stub_test.go и убедимся, что все импорты указывают на ваш текущий проект. В нашем случае это: Запустим тесты: Если все сделано правильно, то после окончания тестирования будет похожий результат: Если у вас возникли проблемы, скачайте исходные файлы и повторите шаги, описанные в этом руководстве. Perigord — это надежный инструмент для тестирования, написанный на вашем любимом языке. Он создает такую же структуру проекта, как Truffle, и имеет такие же команды, поэтому вам не нужно будет переучиваться. Статическая типизация и однозначная сигнатура функций позволяют быстро разрабатывать и выполнять отладку, а также в значительной мере защищают от опечаток в аргументах. В Perigord можно легко мигрировать существующий проект на Truffle (все что вам нужно — скопировать и вставить файлы контрактов в соответствующую папку и добавить тесты), а также начать абсолютно новый проект с тестами, написанными на Go.  Я надеюсь, что работа, начатая командой PolySwarm и продолженная Inn4Science, будет полезна для Go-сообщества и освободит от часов тестирования и отладки с помощью менее удобных инструментов.