Вступ до Ethereum для розробників на Python, частина 1
Отже, ви чули про таку річ, як Ethereum, і готові пірнути в кролячу нору? У цій статті ми швидко розглянемо деякі основи блокчейну, а потім ви зможете взаємодіяти з імітованим вузлом Ethereum: читати дані блоків, перевіряти баланси рахунків і надсилати транзакції. Попутно ми підкреслимо відмінності між традиційними способами створення застосунків і цією новою децентралізованою парадигмою.
(Необов'язкові) попередні вимоги
Ця стаття має на меті бути доступною для широкого кола розробників. Будуть використовуватися інструменти Python, але вони лише засіб для демонстрації ідей – не хвилюйтеся, якщо ви не є розробником на Python. Однак я зроблю кілька припущень щодо того, що ви вже знаєте, щоб ми могли швидше перейти до специфіки Ethereum.
Припущення:
- Ви вмієте користуватися терміналом,
- Ви написали кілька рядків коду на Python,
- На вашому комп’ютері встановлено Python версії 3.6 або новішої (наполегливо рекомендується використовувати віртуальне середовище (opens in a new tab)), і
- ви користувалися
pip, інсталятором пакунків Python. Знову ж таки, якщо щось із цього не відповідає дійсності або ви не плануєте відтворювати код із цієї статті, ви, імовірно, все одно зможете без проблем стежити за викладом.
Коротко про блокчейни
Існує багато способів описати Ethereum, але в його основі лежить блокчейн. Блокчейни складаються з послідовності блоків, тож почнімо з цього. Простіше кажучи, кожен блок у блокчейні Ethereum — це лише деякі метадані та список транзакцій. У форматі JSON це виглядає приблизно так:
1{2 "number": 1234567,3 "hash": "0xabc123...",4 "parentHash": "0xdef456...",5 ...,6 "transactions": [...]7}Кожен блок має посилання на попередній блок; parentHash — це просто хеш попереднього блоку.
Блокчейн — це, по суті, зв’язний список; кожен блок має посилання на попередній.
Ця структура даних не є чимось новим, але правила (тобто однорангові протоколи), які керують мережею, — є. Немає центрального органу влади; мережа рівноправних учасників повинна співпрацювати для підтримки мережі та конкурувати за право вирішувати, які транзакції включати в наступний блок. Отже, коли ви хочете надіслати гроші другові, вам потрібно буде транслювати цю транзакцію в мережу, а потім чекати, доки її буде включено до одного з наступних блоків.
Єдиний спосіб для блокчейну перевірити, що гроші дійсно були надіслані від одного користувача іншому, — це використовувати власну валюту цього блокчейну (тобто створену та керовану ним). У Ethereum ця валюта називається «етер», і блокчейн Ethereum містить єдиний офіційний запис балансів рахунків.
Нова парадигма
Цей новий децентралізований технологічний стек породив нові інструменти для розробників. Такі інструменти існують для багатьох мов програмування, але ми розглядатимемо їх крізь призму Python. Повторимо: навіть якщо Python — не та мова, якій ви віддаєте перевагу, вам не складе труднощів стежити за матеріалом.
Розробники на Python, які хочуть взаємодіяти з Ethereum, найімовірніше, скористаються Web3.py (opens in a new tab). Web3.py — це бібліотека, яка значно спрощує спосіб підключення до вузла Ethereum, а також надсилання та отримання даних із нього.
Клієнти Ethereum можна налаштувати так, щоб вони були доступні через IPC (opens in a new tab), HTTP або WebSocket, тому Web3.py повинен буде віддзеркалювати цю конфігурацію. Web3.py називає ці варіанти підключення провайдерами. Вам потрібно буде вибрати одного з трьох провайдерів, щоб зв'язати екземпляр Web3.py з вашим вузлом.
Налаштуйте вузол Ethereum і Web3.py для зв’язку за тим самим протоколом, наприклад, IPC, як на цій діаграмі.
Щойно Web3.py буде правильно налаштовано, ви зможете почати взаємодіяти з блокчейном. Ось кілька прикладів використання Web3.py як анонс того, що буде далі:
1# зчитати дані блоку:2w3.eth.get_block('latest')34# надіслати транзакцію:5w3.eth.send_transaction({'from': ..., 'to': ..., 'value': ...})Встановлення
У цьому покроковому керівництві ми будемо працювати лише в інтерпретаторі Python. Ми не будемо створювати жодних каталогів, файлів, класів чи функцій.
$, призначені для виконання в терміналі. (Не вводьте символ $, він лише позначає початок рядка.)Спочатку встановіть IPython (opens in a new tab), щоб отримати зручне середовище для дослідження. IPython пропонує, серед іншого, автодоповнення за допомогою клавіші Tab, що значно полегшує вивчення можливостей Web3.py.
pip install ipythonWeb3.py опубліковано під назвою web3. Встановіть його так:
pip install web3Ще один момент: пізніше ми будемо імітувати блокчейн, для чого знадобиться ще кілька залежностей. Ви можете встановити їх за допомогою:
pip install 'web3[tester]'Тепер ви готові до роботи!
Примітка: пакунок web3[tester] працює до версії Python 3.10.xx
Запустіть пісочницю
Відкрийте нове середовище Python, запустивши ipython у вашому терміналі. Це схоже на запуск python, але з більшою кількістю додаткових можливостей.
ipythonБуде виведено певну інформацію про версії Python та IPython, які ви використовуєте, після чого ви побачите запрошення до введення:
1In [1]:Тепер ви бачите інтерактивну оболонку Python. По суті, це пісочниця для експериментів. Якщо ви дійшли до цього етапу, час імпортувати Web3.py:
1In [1]: from web3 import Web3Знайомство з модулем Web3
Окрім того, що модуль Web3 (opens in a new tab) є шлюзом до Ethereum, він пропонує кілька зручних функцій. Розглянемо кілька з них.
У застосунку Ethereum вам часто доведеться конвертувати номінали валюти. Модуль 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 та з wei. Зверніть увагу, що існують назви для багатьох номіналів (opens in a new tab) між етером і wei. Однією з найвідоміших серед них є gwei, оскільки саме так часто представляють комісію за транзакції.
1In [2]: Web3.to_wei(1, 'ether')2Out[2]: 100000000000000000034In [3]: Web3.from_wei(500000000, 'gwei')5Out[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 для зв'язку з вузлом Ethereum. Тут ми можемо використовувати провайдери IPC, HTTP або Websocket.
Ми не будемо йти цим шляхом, але приклад повного робочого процесу з використанням HTTP-провайдера може виглядати приблизно так:
- Завантажте вузол Ethereum, наприклад, 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. Цей тестовий провайдер пов’язаний з імітованим вузлом Ethereum зі спрощеними дозволами та фальшивою валютою для експериментів.
EthereumTesterProvider підключається до імітованого вузла і є зручним для швидкого створення середовищ розробки.
Цей імітований вузол називається eth-tester (opens in a new tab), і ми встановили його як частину команди pip install web3[tester]. Налаштувати Web3.py для використання цього тестового провайдера дуже просто:
1In [4]: w3 = Web3(Web3.EthereumTesterProvider())Тепер ви готові підкорювати ланцюг! Насправді, так ніхто не каже. Я щойно це вигадав. Давайте влаштуємо короткий тур.
Короткий тур
Перш за все, перевірка працездатності:
1In [5]: w3.is_connected()2Out[5]: TrueОскільки ми використовуємо тестовий провайдер, це не дуже цінний тест, але якщо він не вдається, швидше за все, ви зробили помилку при створенні змінної w3. Переконайтеся, що ви включили внутрішні дужки, тобто Web3.EthereumTesterProvider().
Зупинка 1: рахунки
Для зручності тестовий провайдер створив кілька рахунків і попередньо поповнив їх тестовим етером.
Спочатку подивімося на список цих рахунків:
1In [6]: w3.eth.accounts2Out[6]: ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',3 '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',4 '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', ...]Якщо ви виконаєте цю команду, ви побачите список з десяти рядків, які починаються з 0x. Кожен із них є публічною адресою і в певному сенсі аналогічний номеру поточного банківського рахунку. Ви б надали цю адресу тому, хто хотів би надіслати вам етер.
Як уже згадувалося, тестовий провайдер попередньо поповнив кожен з цих рахунків деякою кількістю тестового етеру. Давайте дізнаємося, скільки коштів на першому рахунку:
1In [7]: w3.eth.get_balance(w3.eth.accounts[0])2Out[7]: 1000000000000000000000000Це дуже багато нулів! Перш ніж сміятися по дорозі до фальшивого банку, згадайте попередній урок про номінали валют. Значення етеру представлені в найменшому номіналі, wei. Конвертуймо це в етер:
1In [8]: w3.from_wei(1000000000000000000000000, 'ether')2Out[8]: Decimal('1000000')Один мільйон тестових етерів — все ще непогано.
Зупинка 2: дані блоку
Давайте поглянемо на стан цього імітованого блокчейну:
1In [9]: w3.eth.get_block('latest')2Out[9]: AttributeDict({3 'number': 0,4 'hash': HexBytes('0x9469878...'),5 'parentHash': HexBytes('0x0000000...'),6 ...7 'transactions': []8})Про блок повертається багато інформації, але тут варто зазначити лише кілька речей:
- Номер блоку — нуль, незалежно від того, як давно ви налаштували тестовий провайдер. На відміну від реальної мережі Ethereum, яка додає новий блок кожні 12 секунд, ця симуляція чекатиме, поки ви не дасте їй якусь роботу.
transactions— це порожній список з тієї ж причини: ми ще нічого не зробили. Цей перший блок є порожнім блоком, призначеним лише для запуску ланцюга.- Зверніть увагу, що
parentHash— це просто набір порожніх байтів. Це означає, що це перший блок у ланцюзі, також відомий як початковий блок.
Зупинка 3: транзакції
Ми застрягли на нульовому блоці, поки не з’явиться транзакція в очікуванні, тож давайте її створимо. Надішлімо кілька тестових етерів з одного рахунку на інший:
1In [10]: tx_hash = w3.eth.send_transaction({2 'from': w3.eth.accounts[0],3 'to': w3.eth.accounts[1],4 'value': w3.to_wei(3, 'ether'),5 'gas': 210006})Зазвичай, на цьому етапі ви б чекали кілька секунд, поки ваша транзакція не буде включена до нового блоку. Повний процес виглядає приблизно так:
- Надішліть транзакцію та збережіть її хеш. Поки блок, що містить транзакцію, не буде створено та розповсюджено, транзакція є «в очікуванні».
tx_hash = w3.eth.send_transaction({ … }) - Зачекайте, поки транзакцію буде включено в блок:
w3.eth.wait_for_transaction_receipt(tx_hash) - Продовжуйте логіку застосунку. Щоб переглянути успішну транзакцію:
w3.eth.get_transaction(tx_hash)
Наше імітоване середовище миттєво додасть транзакцію до нового блоку, тож ми можемо одразу переглянути її:
1In [11]: w3.eth.get_transaction(tx_hash)2Out[11]: AttributeDict({3 'hash': HexBytes('0x15e9fb95dc39...'),4 'blockNumber': 1,5 'transactionIndex': 0,6 'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',7 'to': '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',8 'value': 3000000000000000000,9 ...10})Показати всеТут ви побачите знайомі деталі: поля from, to та value мають відповідати вхідним даним нашого виклику send_transaction. Ще один момент, що підтверджує успішність, — це те, що ця транзакція була включена як перша транзакція ('transactionIndex': 0) у блок номер 1.
Ми також можемо легко перевірити успішність цієї транзакції, перевіривши баланси двох залучених рахунків. Три етери мали перейти з одного рахунку на інший.
1In [12]: w3.eth.get_balance(w3.eth.accounts[0])2Out[12]: 99999699997900000000000034In [13]: w3.eth.get_balance(w3.eth.accounts[1])5Out[13]: 1000003000000000000000000Останній виглядає добре! Баланс змінився з 1 000 000 до 1 000 003 етерів. Але що сталося з першим рахунком? Здається, він втратив трохи більше, ніж три етери. На жаль, у житті нічого не буває безкоштовним, і використання публічної мережі Ethereum вимагає, щоб ви компенсували іншим учасникам їхню допоміжну роль. З рахунку, який ініціював транзакцію, було вирахувано невелику комісію за транзакцію. Ця комісія складається з кількості спаленого газу (21 000 одиниць газу для переказу ETH), помноженої на базову комісію, яка змінюється залежно від активності мережі, плюс чайові, які отримує валідатор, що включає транзакцію в блок.
Докладніше про газ
І видихніть
Ми займаємося цим уже деякий час, тому це чудове місце, щоб зробити перерву. Кроляча нора продовжується, і ми продовжимо її досліджувати в другій частині цієї серії. Деякі майбутні концепції: підключення до реального вузла, смарт-контракти та токени. Маєте додаткові запитання? Дайте мені знати! Ваш відгук вплине на те, куди ми рухатимемося далі. Запити приймаються через Twitter (opens in a new tab).
Останні оновлення сторінки: 6 лютого 2025 р.


