Отправка 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

Экран после первого запуска Ganache

После инициализации нашего локального ethereum блокчейна, видим 10 тестовых аккаунтов. Каждый аккаунт имеет баланс по 100 ETH

Рабочее пространство Ganache с 10-ю аккаунтами

Всё, 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 создал бы для нас пустой проект с файлом конфигурации и пустыми каталогами:

Окружение после выполнения команды $ truffle init

Данная структура проекта предназначена для разработки 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.

Ganache отображает баланс в ETH

Итак, у нас всё готово для запуска транзакции. Запускаем саму транзакцию:

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 :)