Перейти к основному контенту

Введение в Эфириум для Python-разработчиков, часть 1

Python
web3.py
Для начинающих
Марк Гарро
8 сентября 2020 г.
11 минут на чтение
Редактировать страницу (opens in a new tab)

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

(Мягкие) предварительные требования

Эта статья стремится быть доступной для широкого круга разработчиков. Будут задействованы инструменты Python, но они служат лишь средством передачи идей — ничего страшного, если вы не являетесь Python-разработчиком. Однако я сделаю несколько предположений о том, что вы уже знаете, чтобы мы могли быстро перейти к специфичным для Эфириума деталям.

Предположения:

  • Вы умеете работать в терминале,
  • Вы написали хотя бы несколько строк кода на Python,
  • На вашем компьютере установлен Python версии 3.6 или выше (настоятельно рекомендуется использовать виртуальную среду (opens in a new tab)), и
  • вы использовали pip, установщик пакетов Python. Опять же, если что-то из этого не так, или вы не планируете воспроизводить код из этой статьи, вы, скорее всего, все равно сможете без проблем следить за ходом мысли.

Кратко о блокчейнах

Есть много способов описать Эфириум, но в его основе лежит блокчейн. Блокчейны состоят из серии блоков, поэтому давайте начнем с них. Проще говоря, каждый блок в блокчейне Эфириума — это просто некоторые метаданные и список транзакций. В формате JSON это выглядит примерно так:

{
   "number": 1234567,
   "hash": "0xabc123...",
   "parentHash": "0xdef456...",
   ...,
   "transactions": [...]
}

Каждый блок имеет ссылку на предшествующий ему блок; parentHash — это просто хеш предыдущего блока.

Примечание: Эфириум регулярно использует хеш-функции для создания значений фиксированного размера («хешей»). Хеши играют важную роль в Эфириуме, но пока вы можете смело думать о них как об уникальных идентификаторах.

A diagram depicting a blockchain including the data inside  each block

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

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

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

Новая парадигма

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

Python-разработчики, которые хотят взаимодействовать с Эфириумом, скорее всего, обратятся к Web3.py (opens in a new tab). Web3.py — это библиотека, которая значительно упрощает способ подключения к узлу Эфириума, а также отправку и получение данных от него.

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

Клиенты Эфириума могут быть настроены для доступа по IPC (opens in a new tab), HTTP или Websockets, поэтому Web3.py должен будет отражать эту конфигурацию. Web3.py называет эти варианты подключения провайдерами (providers). Вам нужно будет выбрать одного из трех провайдеров, чтобы связать экземпляр Web3.py с вашим узлом.

A diagram showing how web3.py uses IPC to connect your application to an Ethereum node

Настройте узел Эфириума и Web3.py для связи по одному и тому же протоколу, например, IPC на этой диаграмме.

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

# прочитать данные блока:
w3.eth.get_block('latest')

# отправить транзакцию:
w3.eth.send_transaction({'from': ..., 'to': ..., 'value': ...})

Установка

В этом руководстве мы будем работать только в интерпретаторе Python. Мы не будем создавать никаких каталогов, файлов, классов или функций.

Примечание: в примерах ниже команды, начинающиеся с $, предназначены для запуска в терминале. (Не вводите $, это просто обозначает начало строки.)

Сначала установите IPython (opens in a new tab) для создания удобной среды для изучения. IPython предлагает автодополнение по нажатию Tab, среди прочих функций, что значительно упрощает понимание того, что возможно в Web3.py.

pip install ipython

Web3.py публикуется под именем web3. Установите его следующим образом:

pip install web3

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

pip install 'web3[tester]'

Все готово к работе!

Примечание: пакет web3[tester] работает с версиями Python до 3.10.xx.

Запуск песочницы

Откройте новую среду Python, запустив ipython в вашем терминале. Это сравнимо с запуском python, но с большим количеством дополнительных возможностей.

ipython

Это выведет некоторую информацию о версиях Python и IPython, которые вы используете, после чего вы должны увидеть приглашение, ожидающее ввода:

In [1]:

Сейчас вы смотрите на интерактивную оболочку Python. По сути, это песочница для экспериментов. Если вы дошли до этого момента, пришло время импортировать Web3.py:

In [1]: from web3 import Web3

Знакомство с модулем Web3

Помимо того, что модуль Web3 (opens in a new tab) является шлюзом в Эфириум, он предлагает несколько удобных функций. Давайте рассмотрим парочку из них.

В приложении на Эфириуме вам часто потребуется конвертировать номиналы валют. Модуль Web3 предоставляет пару вспомогательных методов специально для этого: from_wei (opens in a new tab) и to_wei (opens in a new tab).

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

Аналогичный паттерн используется при обработке транзакций в эфире. Однако вместо двух десятичных знаков эфир имеет 18! Наименьший номинал эфира называется Wei, поэтому именно это значение указывается при отправке транзакций.

1 эфир = 1000000000000000000 Wei

1 Wei = 0.000000000000000001 эфира

Попробуйте конвертировать некоторые значения в Wei и обратно. Обратите внимание, что существуют названия для многих номиналов (opens in a new tab) между эфиром и Wei. Одним из наиболее известных среди них является Gwei, поскольку именно в нем часто выражаются комиссии за транзакции.

In [2]: Web3.to_wei(1, 'ether')
Out[2]: 1000000000000000000

In [3]: Web3.from_wei(500000000, 'gwei')
Out[3]: Decimal('0.5')

Другие служебные методы модуля Web3 включают конвертеры форматов данных (например, toHex (opens in a new tab)), вспомогательные функции для адресов (например, isAddress (opens in a new tab)) и хеш-функции (например, keccak (opens in a new tab)). Многие из них будут рассмотрены позже в этой серии. Чтобы просмотреть все доступные методы и свойства, воспользуйтесь автодополнением IPython, введя Web3. и дважды нажав клавишу Tab после точки.

Общение с цепью

Удобные методы — это прекрасно, но давайте перейдем к блокчейну. Следующий шаг — настроить Web3.py для связи с узлом Эфириума. Здесь у нас есть возможность использовать провайдеры IPC, HTTP или Websocket.

Мы не пойдем по этому пути, но пример полного рабочего процесса с использованием HTTP-провайдера может выглядеть примерно так:

  • Загрузите узел Эфириума, например, Geth (opens in a new tab).
  • Запустите Geth в одном окне терминала и дождитесь синхронизации сети. HTTP-порт по умолчанию — 8545, но его можно настроить.
  • Укажите Web3.py подключиться к узлу по HTTP на localhost:8545. w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545'))
  • Используйте экземпляр w3 для взаимодействия с узлом.

Хотя это один из «реальных» способов сделать это, процесс синхронизации занимает часы и не нужен, если вам просто нужна среда разработки. Для этой цели Web3.py предоставляет четвертого провайдера — EthereumTesterProvider. Этот тестовый провайдер подключается к симулированному узлу Эфириума с ослабленными разрешениями и фальшивой валютой для экспериментов.

A diagram showing the EthereumTesterProvider linking your web3.py application to a simulated Ethereum node

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

Этот симулированный узел называется eth-tester (opens in a new tab), и мы установили его как часть команды pip install web3[tester]. Настроить Web3.py для использования этого тестового провайдера так же просто, как:

In [4]: w3 = Web3(Web3.EthereumTesterProvider())

Теперь вы готовы к серфингу по цепи! Так никто не говорит. Я только что это выдумал. Давайте проведем краткую экскурсию.

Краткая экскурсия

Первым делом, проверка работоспособности:

In [5]: w3.is_connected()
Out[5]: True

Поскольку мы используем тестового провайдера, это не очень ценный тест, но если он завершится неудачей, скорее всего, вы ввели что-то неправильно при создании экземпляра переменной w3. Дважды проверьте, что вы включили внутренние скобки, т. е. Web3.EthereumTesterProvider().

Остановка №1: аккаунты

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

Сначала давайте посмотрим список этих аккаунтов:

In [6]: w3.eth.accounts
Out[6]: ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',
 '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',
 '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', ...]

Если вы выполните эту команду, вы должны увидеть список из десяти строк, которые начинаются с 0x. Каждая из них является публичным адресом и в некотором роде аналогична номеру расчетного счета. Вы бы предоставили этот адрес тому, кто захотел бы отправить вам эфир.

Как уже упоминалось, тестовый провайдер предварительно пополнил каждый из этих аккаунтов некоторым количеством тестового эфира. Давайте узнаем, сколько средств на первом аккаунте:

In [7]: w3.eth.get_balance(w3.eth.accounts[0])
Out[7]: 1000000000000000000000000

Это много нулей! Прежде чем вы с радостью побежите в фальшивый банк, вспомните тот урок о номиналах валют, который был ранее. Значения эфира представлены в наименьшем номинале — Wei. Конвертируйте это в эфир:

In [8]: w3.from_wei(1000000000000000000000000, 'ether')
Out[8]: Decimal('1000000')

Один миллион тестовых эфиров — все равно неплохо.

Остановка №2: данные блока

Давайте взглянем на состояние этого симулированного блокчейна:

In [9]: w3.eth.get_block('latest')
Out[9]: AttributeDict({
   'number': 0,
   'hash': HexBytes('0x9469878...'),
   'parentHash': HexBytes('0x0000000...'),
   ...
   'transactions': []
})

О блоке возвращается много информации, но здесь стоит отметить лишь пару моментов:

  • Номер блока равен нулю — независимо от того, как давно вы настроили тестового провайдера. В отличие от реальной сети Эфириум, которая добавляет новый блок каждые 12 секунд, эта симуляция будет ждать, пока вы не дадите ей какую-нибудь работу.
  • transactions — это пустой список по той же причине: мы еще ничего не сделали. Этот первый блок является пустым блоком, просто чтобы запустить цепь.
  • Обратите внимание, что parentHash — это просто набор пустых байтов. Это означает, что это первый блок в цепи, также известный как генезис-блок.

Остановка №3: транзакции

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

In [10]: tx_hash = w3.eth.send_transaction({
   'from': w3.eth.accounts[0],
   'to': w3.eth.accounts[1],
   'value': w3.to_wei(3, 'ether'),
   'gas': 21000
})

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

  1. Отправьте транзакцию и сохраните хеш транзакции. Пока блок, содержащий транзакцию, не будет создан и транслирован, транзакция является «ожидающей» (pending). tx_hash = w3.eth.send_transaction({ … })
  2. Дождитесь включения транзакции в блок: w3.eth.wait_for_transaction_receipt(tx_hash)
  3. Продолжите логику приложения. Чтобы просмотреть успешную транзакцию: w3.eth.get_transaction(tx_hash)

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

Здесь вы увидите некоторые знакомые детали: поля from, to и value должны совпадать с входными данными нашего вызова send_transaction. Еще один обнадеживающий момент заключается в том, что эта транзакция была включена как первая транзакция ('transactionIndex': 0) в блок номер 1.

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

In [12]: w3.eth.get_balance(w3.eth.accounts[0])
Out[12]: 999996999979000000000000

In [13]: w3.eth.get_balance(w3.eth.accounts[1])
Out[13]: 1000003000000000000000000

Последнее выглядит отлично! Баланс увеличился с 1 000 000 до 1 000 003 эфиров. Но что случилось с первым аккаунтом? Похоже, он потерял чуть больше трех эфиров. Увы, в жизни нет ничего бесплатного, и использование публичной сети Эфириум требует, чтобы вы компенсировали своим узлам-партнерам их вспомогательную роль. С аккаунта, отправившего транзакцию, была списана небольшая комиссия за транзакцию — эта комиссия равна количеству сожженного газа (21 000 единиц газа за перевод ETH), умноженному на базовую комиссию, которая варьируется в зависимости от активности сети, плюс чаевые, которые идут валидатору, включающему транзакцию в блок.

Подробнее о газе

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

И выдохните

Мы занимаемся этим уже некоторое время, так что это место кажется отличным для того, чтобы сделать перерыв. Кроличья нора продолжается, и мы продолжим исследование во второй части этой серии. Некоторые из предстоящих концепций: подключение к реальному узлу, смарт-контракты и токены. Есть дополнительные вопросы? Дайте мне знать! Ваши отзывы повлияют на то, куда мы двинемся дальше. Пожелания приветствуются через Твиттер (opens in a new tab).

Последнее обновление страницы: 3 марта 2026 г.