Как писать обновляемые смарт-контракты с помощью Truffle ^5.0 и ZeppelinOS ^2.0
Контекст
В этом посте мы узнаем, как писать обновляемые смарт-контракты с последними версиями Truffle и ZeppelinOS. В частности, версия ^5.0 Truffle представляет множество обновлений, наиболее заметным из которых является интеграция с web3 ^1.0. Давайте распакуем эти обновления и представим обновляемые смарт-контракты с современной ZeppelinOS.
Это не вводная статья по разработке Ethereum, если хотите, ознакомьтесь со следующими ресурсами:
Обратите внимание, что мир блокчейна движется с невероятной скоростью, практически не оставляя времени для внедрения стандартов. Это означает, что многие фрагменты кода из приведенных выше статей могут работать не так, как ожидалось, но не паникуйте и возвращайтесь сюда, когда что происходит.
Предпосылки
Убедитесь, что у вас есть следующее:
- node.js и нпм
- ганаш-кли или Ганаш настольное приложение
- любопытство узнать больше
Трюфель ^5.0
Чтобы установить трюфель глобально, перейдите в свой терминал и напишите:
$ npm install truffle@^5.0.0 --global
И давайте создадим наш проект:
$ mkdir MyProject
$ cd myProject
$ npm init -y
$ truffle init
Это инициализирует кучу файлов. Если вы использовали более ранние версии Truffle, вы можете заметить, что файл «truffle-config.js» стал более подробным и имеет гораздо больше настраиваемых параметров. Пройдемся по важным изменениям.
Веб3 ^1.0
Это серьезное изменение API, но оно хорошее, потому что новая библиотека намного элегантнее и интуитивно понятна в использовании. Конечно, есть затраты на переход, если вы уже написали свои тесты Truffle, используя более старые версии, поэтому добавьте web3 ^1.0 в закладки. документация на всякий случай.
Провайдер HD-кошелька
Если вы ранее использовали модуль npm «truffle-hdwallet-provider», вы должен обновитесь до «truffle-hdwallet-provider@web3-one», чтобы он работал с Truffle ^5.0:
$ npm install truffle-hdwallet-provider@web3-one --save-dev
Чтобы загрузить свою мнемонику, вы можете либо использовать модуль «fs», изначально предоставленный узлом, либо установить «dotenv». Никогда не кодируйте это в JavaScript!
Принесите свой собственный компилятор
Раньше это был огромный боль в шее изменить компилятор Solidity при компиляции с помощью Truffle, но больше не бойтесь! Вы можете определить любую (удаленную) версию, которую хотите, выполнив следующие действия:
compilers: {
solc: {
optimizer: {
enabled: true,
runs: 200,
},
version: "0.4.25",
},
}
В этом конкретном примере мы установили версию компилятора «0.4.25», но вы можете выбрать «0.4.24» или «0.4.18», если хотите. Чтобы просмотреть все доступные версии:
$ truffle compile --list
Поддержка асинхронного режима, подождите
Если вы поклонник супер-пупер крутых «асинхронных» и «ожидающих» JavaScript ES8, теперь вы можете эффективно использовать их при запуске. $ truffle develop
или же $ truffle console
.
Другие
Есть несколько других новых функций, таких как добавленная поддержка плагинов, но они выходят за рамки этого руководства. Проверьте список изменений если вы ищете исчерпывающий список.
Разверните смарт-контракт
Это макет контракта Solidity, который мы собираемся использовать:
// Note.sol
pragma solidity ^0.4.25;
contract Note {
uint256 private number;
constructor(uint256 _number) public {
number = _number;
}
function getNumber() public view returns (uint256 _number) {
return number;
}
}
Создайте новый файл с именем «Note.sol» в папке «contracts», скопируйте и вставьте туда приведенный выше код. Теперь убедитесь, что вы выполнили все шаги правильно, составив контракт:
$ truffle compile
Вы не должны получить никаких ошибок и следующие журналы:
Компиляция ./contracts/Migrations.sol…
Компиляция ./contracts/Note.sol…
Запись артефактов в ./build/contracts
Теперь давайте напишем файл миграции.
var Note = artifacts.require("./Note.sol");
module.exports = function (deployer) {
deployer.deploy(Note, 64);
};
В папке «migrations» создайте новый файл с именем «2_migrate_note.js» и скопируйте и вставьте приведенный выше код. Чтобы проверить настройку, вам нужно сначала раскрутить узел Ethereum, но не волнуйтесь, для локальной разработки есть такие инструменты, как Ганаш. Вы можете запустить его, открыв новое окно терминала и выполнив $ ganache-cli
или запустив настольное приложение. Затем:
$ truffle migrate
Если вы столкнулись с проблемами, убедитесь, что ваш файл «truffle-config.js» выглядит так (для краткости я убрал комментарии):
module.exports = {
compilers: {
solc: {
version: "0.4.25",
settings: {
optimizer: {
enabled: false,
runs: 200
}
}
}
},
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*",
}
}
};
Если это сработает, вы должны получить красивый отчет, подобный один здесь. Потрясающий! Теперь вы знаете, как скомпилировать и развернуть контракт с Truffle ^5.0, но вы еще не запачкали руки более интересной частью: сделать смарт-контракты обновляемыми.
ZeppelinОС
Настраивать
Если вы совсем не знакомы с обновляемыми смарт-контрактами, посмотрите фильм Елены Надолински. презентация по теме. Это того стоит, и это может сделать работу намного лучше, чем кто-либо в блоге.
Суть в том, что мы стремимся согласовать традиционные методы разработки со смарт-контрактами:
- При проведении A/B-тестирования с реальными пользователями и обнаружении ошибки мы должны исправить код как можно скорее.
- Процессы обновления должны оставаться полностью прозрачными и не предоставлять полную власть разработчику (разработчикам).
Точка № 2 в настоящее время активно исследуется многими людьми предложение прозрачные модели управления. Однако пока мы не будем возражать против децентрализованных автономных организаций (ДАО) и сосредоточимся на технической части истории.
Давайте установим ZeppelinOS и его библиотечную зависимость:
npm install zos --global
npm install zos-lib --save-dev
А затем инициализируем его в нашем проекте Truffle:
zos init MyProject
Файл с именем «zos.json» должен был быть инициализирован:
{
"zosversion": "2",
"name": "MyProject",
"version": "0.1.0",
"contracts": {}
}
Главное, убедитесь, обновить контракт Note следующим образом:
// Note.sol
pragma solidity ^0.4.25;
import "zos-lib/contracts/Initializable.sol";
contract Note is Initializable {
uint256 private number;
function initialize(uint256 _number) public initializer {
number = _number;
}
function getNumber() public view returns (uint256 _number) {
return number;
}
}
Контракты ZeppelinOS не используют обычные конструкторы Solidity, а вместо этого полагаются на «инициализируемый» базовый контракт, для которого необходимо переопределить функцию «инициализации». Продолжим добавлением отредактированного контракта в ZeppelinOS:
$ zos add Note
Следующий объект JavaScript должен был быть добавлен в «zos.json»:
"contracts": {
"Note": "Note"
}
Перед развертыванием ZeppelinOS требует от вас создания сеанса:
$ zos session --network development --from YOUR_DEPLOYMENT_ACCOUNT --expires 7200
Объяснение каждого параметра:
- сеть: одна из сетей, определенных в «truffle-config.js»
- от: из-за известного проблема с прозрачным проксиучетная запись развертывания не должна быть адресом по умолчанию, обозначенным трюфелем или ганашем.
- expires: время жизни сеанса, измеряемое в секундах
Теперь, чтобы уточнить несколько вещей:
- Сессия является своего рода «поведенческим сахаром» — при развертывании вам не нужно указывать параметры «сеть» и «от».
- Вы можете задаться вопросом, какой параметр «от» установить. Проще говоря, любой аккаунт кроме первый. Найдите изображение ниже для примера в настольном приложении Ganache:
Готовы к прайм-тайму?
$ zos push
Если это сработало, у вас должно было получиться что-то вроде этого:
Составление договоров
Компиляция ./contracts/Migrations.sol…
Компиляция ./contracts/Note.sol…
Компиляция zos-lib/contracts/Initializable.sol…
Запись артефактов в ./build/contractsПодтверждение контракта Примечание
Загрузка контракта Note как Note
Развертывание логического контракта для Note
Создан zos.dev-7923.json
Эта команда, наконец, развертывает ваш смарт-контракт в блокчейне, а также создает файл с именем «zos.dev-
Возможность обновления
Очень важно понимать, что внутри ZeppelinOS работает, создавая два контракта:
- Прокси
- Логика
Загвоздка в том, что Прокси перенаправляет конечного пользователя на Логику, но Прокси «удерживает» хранилище. То есть, даже если вы обновите логику, состояние ваших смарт-контрактов останется прежним.
Ранее вы создали и развернули контракт Logic. Давайте создадим экземпляр прокси:
$ zos create Note --init initialize --args 64
Это развертывает и регистрирует адрес нового прокси-контракта. Откройте новое окно терминала и инициализируйте консоль Truffle:
truffle console --network development
let abi = require("./build/contracts/Note.json").abi
let contract = new web3.eth.Contract(abi, "your-proxy-address")
contract.methods.getNumber().call();
Он должен напечатать «64».
Перейти в Интернет3 ^1.0 документы для получения дополнительной информации о том, как работать с новым Contract API.
Что делать, если вы хотите изменить номер? К счастью, можно сделать апгрейд логики контракта, сохранив при этом хранилище.
Во-первых, обновите контракт, добавив новую функцию:
// Note.sol
pragma solidity ^0.4.25;
import "zos-lib/contracts/Initializable.sol";
contract Note is Initializable {
uint256 private number;
function initialize(uint256 _number) public initializer {
number = _number;
}
function getNumber() public view returns (uint256 _number) {
return number;
}
function setNumber(uint256 _number) public {
number = _number;
}
}
А потом:
$ zos push
$ zos update Note
Логи должны выглядеть так:
Использование сеанса с развитием сети, адрес отправителя 0xd833B5fa468A5a430a890390D8Ec652142836019
Обновление прокси до логического контракта 0xe6d6d1cd339f129275e5b5e7ab39d85bc5642010
Экземпляр по адресу 0x746bb4a872bdfd861c4af5dd9391b3fb5b22fb7a обновлен
0x746bb4a872bdfd861c4af5dd9391b3fb5b22fb7a
Обновлен zos.dev-7923.json.
Теперь запустите новую консоль Truffle и вызовите новую функцию setNumber:
$ truffle console --network development
let abi = require("./build/contracts/Note.json").abi;
let contract = new web3.eth.Contract(abi, "your-proxy-address");
contract.methods.getNumber().call();
contract.methods.setNumber(65).send({ from: YOUR_OTHER_ACCOUNT });
contract.methods.getNumber().call();
Он должен напечатать «65».
Предостережения
- YOUR_DEPLOYMENT_ACCOUNT должен использоваться только при настройке сеанса, для любого другого взаимодействия с контрактом вы должны использовать другую учетную запись.
- Если у вас есть
A network name must be provided to execute the requested action
ошибка, просто начните новый сеанс, срок действия старого истек. - Вы могли заметить, что мы не использовали TruffleContract для взаимодействия с развернутыми контрактами, а вместо этого полагались на реализацию web3 ^1.0. Это потому, что я нахожу первое сбивающим с толку и во многих случаях[1][2]даже не функционально.
- Обновляемые смарт-контракты — это нечто большее, чем то, что мы обсуждали здесь. Отправляйтесь в удивительный Zeppelin документация чтобы получить полную картину. В частности, я рекомендую ознакомиться с ограничения к обновлению переменных хранилища.
Если вы планируете перейти на Solidity ^0.5.0, мне жаль вас разочаровывать, поскольку ZeppelinOS еще не поддерживает ее по состоянию на декабрь 2018 года. Существует опция «—skip-compile», но я чувствовал, что это добавило слишком много сложности, чтобы оно того стоило.Сантьяго Палладино из Zeppelin потянулся в Твиттере и объявили, что теперь они поддерживают версии Solidity ^0.5.0. Если вы хотите проверить это, просто сделайтеnpm install zos-lib@2.1.0-rc.0 --global
.
Заворачивать
Надеюсь, вам понравился этот урок, и вы так же увлечены разработкой блокчейна, как и я, несмотря на случайные проблемы с версиями и координацией.
Я скомпилировал код, использованный в этой статье, на этом GitHub. репо. Есть три ветки (master, zos, zos-upgrade) с соответствующим кодом контракта Note для каждого пройденного нами этапа.
Найди меня на Твиттер или же База ключей если вы хотите поболтать.