Локальное окружение для изучения Web3.js и Ethereum
В данной статье я расскажу как настроить окружение для изучения библиотеки web3.js Статья рассчитана на тех, кто интересуется blockchain и хочет научиться взаимодействовать с сетью Ethereum, она же EVM (Ethereum Virtual Machine), через библиотеку web3.js
После настройки окружения, мы отправим нашу первую транзакцию - перевод криптовалюты с одного аккаунта на другой посредством библиотеки web3, а так же изучим некоторые другие команды. После данного руководства не составит труда поэкспериментировать и с остальными методами библиотеки, ознакомившись с документацией web3 API.
Что нам понадобится?
Ganache
Node.js
JS библиотека truffle
Что такое web3.js?
Согласно официальной документации, web3.js это Ethereum JavaScript API, содержащий коллекцию библиотек, позволяющих взаимодействовать с локальными или удалёнными ethereum нодами, посредством HTTP, IPC или WebSocket. В нашем случае мы будем взаимодействовать только с локальной нодой, а все наши транзакции будут происходить внутри нашего компьютера.
Что такое Ganache?
Ganache - это локальная Ethereum блокчейн сеть, состоящая всего из одной ноды. По сравнению с боевыми нодами реальных блокчейн сетей, Ganache занимает очень мало места, так как при старте она не содержит никаких данных, кроме самого первого Genesis блока и 10 тестовых акаунтов, имеющих на своём балансе по 100 ETH. Ganache прекрасно подходит для тестирования Dapp приложений, смарт-контрактов и изучения блокчейн сети Ethereum.
Что такое truffle?
Это библиотека, позволяющая взаимодействовать с EVM - Ethereum Virtual Machine, разрабатывать смарт-контракты, компилировать и деплоить их в EVM, отлаживать их, а так же взаимодействовать с ними через консоль. Библиотека включает в себя библиотеку web3.js.
Итак, приступим.
Установка Ganache
Скачиваем дистрибутив, устанавливаем, запускаем приложение и нажимаем Quickstart
После инициализации нашего локального ethereum блокчейна, видим 10 тестовых аккаунтов. Каждый аккаунт имеет баланс по 100 ETH
Всё, ethereum блокчейн установлен, теперь настроим консоль при помощи которой мы будем отправлять сообщения нашему блокчейну.
Устанавливаем библиотеку truffle через npm
Для этого нам понадобится установленная Node.js v14 - v18. Скачать nodejs можно тут. Затем устанавливаем truffle:
$ npm install -g truffle
Проверяем, что всё установилось корректно:
$ truffle version
Вывод:
Truffle v5.8.1 (core: 5.8.1)
Ganache v7.7.7
Solidity - 0.8.19 (solc-js)
Node v18.12.1
Web3.js v1.8.2
Если возникли проблемы, то можно посмотреть официальное руководство по установке.
Заходим в truffle console
Теперь пробуем зайти в консоль:
$ truffle console
Мы видим следующее сообщение:
Could not find suitable configuration file.
Truffle v5.8.1 (core: 5.8.1)
Node v18.12.1
Так произошло, потому что truffle не нашёл файла конфигурации. Но к счастью ничего настраивать нам не нужно, а достаточно создать пустой файл truffle-config.js
и truffle применит настройки по-умолчанию.
Создадим произвольную папку, в ней создадим наш пустой файл настроек и запустим truffle консоль:
$ mkdir web3-demo
$ cd web3-demo
$ touch truffle-config.js
$ truffle console
У нас должна появиться строка консоли:
$ truffle(ganache)>
Примечание: вместо создания вручную пустого файла truffle-config.js
мы могли бы использовать команду
$ truffle init
и тогда truffle создал бы для нас пустой проект с файлом конфигурации и пустыми каталогами:
Данная структура проекта предназначена для разработки smart-контрактов и деплоя их в тестовую сеть Ganache, что не является темой данного топика, поэтому я использовал минимально необходимые настройки.
Тестируем доступ к блокчейн сети через консоль
Набираем в открытой ранее truffle консоли:
web3.eth.getAccounts()
Если мы видим вывод представленный ниже, то всё отлично, мы подключились к нашей тестовой локальной блокчейн EVM. В данном случае мы запросили сеть выдать нам все аккаунты, и они идентичны тем, что мы видели в нашем GUI Ganache. Сами аккаунты могут отличаться, так как Ganache при каждом запуске генерирует новые аккаунты.
[
'0x4DfcE7Fb36c1C95Fd72dE02DB865EfC5c4E72dE8',
'0x968a34AC105aca298209c2dce23A8De721fB3C19',
'0x9a978DaeecA6cdD141c9aDEc7A0AE5F86e48F10d',
'0x2FcF93F05067445886afF6d832d68b8b4E31b0A3',
'0x777C7A81C70B3978a2D2574E2D4939D882f0AA13',
'0xc1a204D8E7e5550C6Cd1c9d2f142F7C3306b0774',
'0x432D3e48DA7FdeAf41933E85C04a401b96bAeefe',
'0x4a47F93Dfe15bA9165C8E6735ffD8D142d238F5c',
'0xA1B19BA4fcC38A86927f4C76e5cEC5Bd027940aC',
'0x47fc50170A8E68D7C6d2855c2d9F1F0412CB5B77'
]
Теперь попробуем отправить криптовалюту с одного аккаунта на другой.
Отправка криптовалюты с одного аккаунта на другой
Для отправки мы воспользуемся следующей командой:
web3.eth.sendTransaction({
from: "0x4DfcE7Fb36c1C95Fd72dE02DB865EfC5c4E72dE8",
to: "0x968a34AC105aca298209c2dce23A8De721fB3C19",
value: web3.utils.toWei("0.01", "ether")
})
Данная команда подписывает приватным ключом отправителя транзакцию, и отправляет её в сеть Ethereum. Сама транзакция представлена в виде javascript объекта.
Значения для полей from
и to
я взял из предыдущего вызова getAccounts()
, это соответствует первому и второму адресу в массиве. Вы можете использовать любые другие адреса.
В поле value мы помещаем сумму, которую хотим отправить. В данном случае я поместил вызов функции, которая сконвертирует значение, выраженное в Ether в значение, выраженное в Wei. Дело в том, что EVM оперирует только значениями выраженными в Wei - это минимальная единица измерения криптовалюты Ethereum. 1 Ether = 10^18 Wei.
Можно прямо сейчас проверить в консоли, какое число бы нам пришлось писать в value, без этой функции:
web3.utils.toWei("0.01", "ether")
Вывод:
'10000000000000000'
Как видим, можно легко запутаться в нулях. Здесь представлены все единицы измерения криптовалюты в Ethereum.
Перед запуском транзакции, проверим состояние балансов наших аккаунтов:
Первый аккаунт:
web3.eth.getBalance("0x4DfcE7Fb36c1C95Fd72dE02DB865EfC5c4E72dE8")
Вывод:
'100000000000000000000'
Второй аккаунт:
web3.eth.getBalance("0x968a34AC105aca298209c2dce23A8De721fB3C19")
Вывод:
'100000000000000000000'
Напомню, что здесь мы видим значение баланса, выраженного в Wei. Можно так же заглянуть в GUI Ganache и убедиться, что всё верно. В GUI баланс отражён в Ether.
Итак, у нас всё готово для запуска транзакции. Запускаем саму транзакцию:
web3.eth.sendTransaction({from: "0x4DfcE7Fb36c1C95Fd72dE02DB865EfC5c4E72dE8", to: "0x968a34AC105aca298209c2dce23A8De721fB3C19", value: web3.utils.toWei("0.01", "ether")})
Если всё прошло успешно, то на выходе получаем js-объект. Это так называемый Receipt
, или квитанция о совершённой транзакции. В ней содержится такая информация, как хэш транзакции (по нему мы можем найти транзакцию в блокчейне), номер блока в который была записана наша транзакция, хэш блока и другая полезная информация.
{
transactionHash: '0x0bf4bd25ab2de3b44e6a60ae7187748f85349eb88f7df1d90a6ce1041ebc827d',
transactionIndex: 0,
blockNumber: 1,
blockHash: '0xa54a964d5db58d84b21d9d29ee1972ffd74501d67fd4432c7cbce0dddc01fe83',
from: '0x4dfce7fb36c1c95fd72de02db865efc5c4e72de8',
to: '0x968a34ac105aca298209c2dce23a8de721fb3c19',
cumulativeGasUsed: 21000,
gasUsed: 21000,
contractAddress: null,
logs: [],
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
status: true,
effectiveGasPrice: 3375000000,
type: '0x2'
}
Итак, транзакция прошла успешно. Теперь проверим балансы наших аккаунтов.
Аккаунт-отправитель:
web3.eth.getBalance("0x4DfcE7Fb36c1C95Fd72dE02DB865EfC5c4E72dE8")
Вывод:
'99989929125000000000'
Аккаунт-получатель:
web3.eth.getBalance("0x968a34AC105aca298209c2dce23A8De721fB3C19")
Вывод:
'100010000000000000000'
Как видим, балансы изменились: у получателя прибавилось 0.01 Ether, а у отправителя списалась сумма, чуть большая, чем 0.01 Ether. Дело в том, что с отправителя списалась ещё и комиссия за транзакцию, которая выражается в Gas. Gas это топливо сети Ethereum, или оплата за пользование вычислительными ресурсами.
Данная комиссия вычисляется путём умножения текущей стоимости 1 единицы Gas на то количество единиц Gas, которое потребуется для выполнения нашей транзакции. В реальной сети Ethereum стоимость 1 единицы Gas постоянно меняется. Здесь можно провести параллель с ценами на бензин на АЗС, и стоимостью поездки из пункта А в пункт Б на личном автомобиле. Общая стоимость проезда в данном случае будет складываться из цены за литр бензина и объёма израсходованного топлива.
Проверяем баланс в GUI Ganache:
Напоследок можно зайти на вкладку Transactions в Ganache, и там увидеть нашу транзакцию.
Зайдём внутрь транзакции, кликнув на неё:
Так же можно зайти на вкладку Blocks и увидеть два блока: нулевой был записан при запуске самой сети Ethereum, это так называемый Genesis Block, следующий блок - это и есть тот блок, куда попала наша транзакция:
Зайдём внутрь первого блока, куда попала наша транзакция:
Если сравнить квитанцию, которая была получена в консоли, с тем что отражено в GUI, то можно убедиться что информация идентична.
На этом всё. Мы настроили окружение и научились отправлять транзакцию через консоль. Для дальнейшего изучения Ethereum, можно воспользоваться официальной документацией к Web3 API.
Например описание получение баланса находится тут. Получить текущую цену на Gas можно этой командой:
web3.eth.getGasPrice()
Вывод:
'20000000000'
При дальнейшем изучении, в данной среде можно деплоить и тестировать smart-контракты.
Спасибо за внимание, всем успехов в освоении web3 :)