Як створити блокчейн за допомогою Python?

Чи відомо вам, що біткойн базується на технології блокчейн? Сьогодні ми разом створимо власний блокчейн на Python, починаючи з самого початку.

Що таке блокчейн?

У 2008 році документ про біткойн був оприлюднений невідомою особою або групою під псевдонімом Сатоші Накамото. Біткойн виник як однорангова система електронних грошей, що дозволяє проводити транзакції без потреби в централізованих посередниках (таких як банки). Мало хто усвідомлює, що в цьому ж документі Сатоші представив децентралізований метод зберігання даних, який сьогодні відомий як блокчейн.

Технологія блокчейн

Простіше кажучи, блокчейн – це спільний, незмінний цифровий реєстр, в якому зберігаються транзакції через децентралізовану мережу комп’ютерів.

Блокчейн можна розкласти на два основні поняття:

  • Блок: місце, де зберігаються транзакції.
  • Ланцюг: послідовність взаємопов’язаних записів.

Отже, блокчейн – це ланцюг пов’язаних блоків, де кожен блок містить транзакції, виконані з певними параметрами.

Кожен новий блок створюється на основі попереднього, утворюючи незворотний ланцюг. Кожен блок залежить від попереднього. Це створює надійну і стійку систему, де будь-хто з відповідними правами може перевірити її цілісність.

Блокчейн надає ряд цікавих можливостей:

  • Непорушність історії транзакцій.
  • Інформаційна стійкість.
  • Відсутність помилок у збережених даних.

Сьогодні блокчейн використовується в багатьох системах, зокрема в криптовалютах, передачі цифрових активів (NFT) та, можливо, в майбутньому, навіть у голосуванні.

Варто зазначити, що блокчейн на Python не обов’язково має бути складним кодом. За своєю суттю, це буде просто список транзакцій, пов’язаних між собою.

Це було коротке пояснення, але якщо вам потрібна глибша інформація, у нас є повний посібник з блокчейну для новачків. Рекомендуємо вам ознайомитися з ним.

Без зайвих зволікань, давайте почнемо створювати простий блокчейн на Python.

Розробка блокчейну з Python

Перш ніж ми почнемо, визначимо, що ми збираємося робити у цьому підручнику:

  • Створимо просту систему блокчейн на Python.
  • Використаємо наш блокчейн з попередньо встановленими транзакціями, представленими у вигляді рядків.
  • Перевіримо незмінність нашого блокчейну.

Ми будемо використовувати не JSON, а списки Python. Це дозволить нам спростити процес і зосередитися на основних концепціях блокчейну.

Що вам знадобиться для проходження цього підручника:

Створення класу Block

Відкрийте ваш улюблений редактор коду і створіть файл з назвою main.py. Це буде файл, з яким ми працюватимемо.

Тепер імпортуйте модуль hashlib, який дозволяє створювати односторонні зашифровані повідомлення. Криптографічні методи, такі як хешування, дозволяють блокчейну створювати безпечні транзакції.

Хеш-функція – це алгоритм, який отримує деякі дані (зазвичай закодований рядок) і повертає унікальний ідентифікатор, часто званий “дайджест” або “підпис”. Ця остання частина є важливою: навіть незначна зміна вхідних даних створює абсолютно інший ідентифікатор на виході. Пізніше ми побачимо це на практиці.

Наразі просто імпортуйте вбудований модуль hashlib:

# main.py файл
"""
Простий блокчейн на Python
"""

import hashlib

Цей модуль містить більшість алгоритмів хешування, які вам можуть знадобитися. Ми будемо використовувати функцію hashlib.sha256().

Тепер перейдемо до GeekCoinBlock – нашої абсолютно оригінальної назви для блоку.

class GeekCoinBlock:

    def __init__(self, previous_block_hash, transaction_list):

        self.previous_block_hash = previous_block_hash
        self.transaction_list = transaction_list

        self.block_data = f"{' - '.join(transaction_list)} - {previous_block_hash}"
        self.block_hash = hashlib.sha256(self.block_data.encode()).hexdigest()

Розумію, що це може виглядати як складний фрагмент коду. Давайте розберемо кожну його частину в наступному розділі.

Пояснення GeekCoinBlock

Спочатку ми створюємо клас під назвою GeekCoinBlock – це оболонка для об’єктів, які матимуть певні характеристики (атрибути) і дії (методи).

Потім ми визначаємо метод __init__ (конструктор), який викликається кожен раз, коли створюється об’єкт GeekCoinBlock.

Цей метод має три параметри:

  • self (екземпляр кожного об’єкта).
  • previous_block_hash (посилання на попередній блок).
  • transaction_list (список транзакцій, здійснених у поточному блоці).

Ми зберігаємо попередній хеш і список транзакцій, а також створюємо змінну екземпляра block_data як рядок. У реальних криптовалютах ми зберігаємо такі дані як інший хеш, але для простоти ми зберігаємо дані кожного блоку як рядок.

Нарешті, ми створюємо block_hash, який інші блоки використовуватимуть для продовження ланцюга. Саме тут стане в нагоді hashlib: замість створення спеціальної хеш-функції, ми можемо використовувати sha256 для створення незмінних блоків.

Ця функція приймає закодовані рядки (або байти) як параметри. Ось чому ми використовуємо метод block_data.encode(). Після цього ми викликаємо hexdigest(), щоб повернути закодовані дані у шістнадцятковому форматі.

Я знаю, що все це може здатися складним, тому давайте пограємося з hashlib в оболонці Python.

In [1]: import hashlib

In [2]: message = "Python is great"

In [3]: h1 = hashlib.sha256(message.encode())

In [4]: h1
Out[4]: <sha256 ... object @ 0x7efcd55bfbf0>

In [5]: h1.hexdigest()
Out[5]: 'a40cf9cca ... 42ab97'

In [6]: h2 = hashlib.sha256(b"Python is not great")

In [7]: h2
Out[7]: <sha256 ... object @ 0x7efcd55bfc90>

In [8]: h2.hexdigest()
Out[8]: 'fefe510a6a ... 97e010c0ea34'

Як бачите, навіть незначна зміна вхідних даних, як-от зміна “Python is great” на “Python is not great”, створює зовсім інший хеш. Це має важливе значення для цілісності блокчейну. Якщо ви внесете хоч невеликі зміни до блокчейну, його хеш радикально зміниться. Саме тому твердження “Ви не можете підробити блокчейн” є правдивим.

Використання класу Block

Згодом ми створимо повний клас Blockchain, а поки що давайте використаємо наш клас Block для створення ланцюжка блоків (блокчейну).

У тому ж файлі створіть кілька транзакцій у вигляді простих рядків, збережених у змінних, наприклад:

class GeekCoinBlock:
    ...

t1 = "Noah sends 5 GC to Mark"
t2 = "Mark sends 2.3 GC to James"
t3 = "James sends 4.2 GC to Alisson"
t4 = "Alisson sends 1.1 GC to Noah"

Звичайно, GC означає GeekCoin.

Тепер створіть перший блок нашого блокчейну за допомогою класу GeekCoinBlock і виведіть його атрибути. Зверніть увагу, що параметр previous_hash для генезис-блоку (першого блоку, що передує всім іншим блокам) завжди буде деяким довільним рядком або хешем, у цьому випадку – “firstblock”.

block1 = GeekCoinBlock('firstblock', [t1, t2])

print(f"Block 1 data: {block1.block_data}")
print(f"Block 1 hash: {block1.block_hash}")

Потім ми робимо те саме з другим блоком, але передаємо хеш першого блоку як аргумент previous_hash.

block2 = GeekCoinBlock(block1.block_hash, [t3, t4])

print(f"Block 2 data: {block2.block_data}")
print(f"Block 2 hash: {block2.block_hash}")

Давайте запустимо і проаналізуємо результат, який ми отримуємо від цього коду. Знову введіть у свій термінал:

❯ python main.py
Block 1 data: Noah sends 5 GC to Mark - Mark sends 2.3 GC to James - firstblock
Block 1 hash: 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d
Block 2 data: James sends 4.2 GC to Alisson - Alisson sends 1.1 GC to Noah - 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d
Block 2 hash: 448c4306caf7f6937b0307f92f27fbea3bb73b3470363dee5026a1209dadcfa8

Зараз ви бачите тільки текст і приблизно 64 символи хешу, але це вже відтворює механізм блокчейну.

Ви починаєте з генезис-блоку, основи всіх інших блоків.

Будь-хто може перевірити цілісність ланцюга, і тому блокчейн є такою безпечною системою. Наприклад, якщо ми трохи змінимо вміст транзакції, наприклад:

t2 = "Mark sends 2.3 GC to James" -> t2 = "Mark sends 3.2 GC to James"

Ми побачимо значні зміни в хеші блоків.

Block 1 data: Noah sends 5 GC to Mark - Mark sends 3.2 GC to James - firstblock
Block 1 hash: 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c
Block 2 data: James sends 4.2 GC to Alisson - Alisson sends 1.1 GC to Noah - 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c
Block 2 hash: 569b977306ce88b53e001dca7ba00c03a51c60d6df4650e7657dcd136f2da0ac

Ви можете переглянути поточний проект на цьому репозиторії GitHub.

Кодування блокчейну

Основою цілісності нашої системи не можуть бути закодовані вручну змінні, тому нам потрібен інший підхід.

У нас є блоки. Тепер настав час створити клас, який об’єднає їх у блокчейн.

Почнемо з видалення попередніх транзакцій і об’єктів блоків, а потім скористаємося наступним кодом.

# main.py

class Blockchain:
    def __init__(self):
        self.chain = []
        self.generate_genesis_block()

    def generate_genesis_block(self):
        self.chain.append(GeekCoinBlock("0", ['Genesis Block']))

    def create_block_from_transaction(self, transaction_list):
        previous_block_hash = self.last_block.block_hash
        self.chain.append(GeekCoinBlock(previous_block_hash, transaction_list))

    def display_chain(self):
        for i in range(len(self.chain)):
            print(f"Data {i + 1}: {self.chain[i].block_data}")
            print(f"Hash {i + 1}: {self.chain[i].block_hash}n")

    @property
    def last_block(self):
        return self.chain[-1]

Знову ж таки, це великий шматок коду. Давайте розберемо кожну частину:

  • self.chain – список, де зберігаються всі блоки. Ми можемо отримати доступ до кожного блоку через індекси списку.
  • generate_genesis_block – додає генезис, або перший блок, до ланцюга. Попередній хеш блоку – “0”, а список транзакцій – просто “Genesis Block”.
  • create_block_from_transaction – дозволяє додавати блоки до ланцюга, використовуючи лише список транзакцій. Було б дуже незручно створювати блок вручну кожного разу, коли ми хочемо зафіксувати транзакцію.
  • display_chain – виводить ланцюжок блоків за допомогою циклу for.
  • last_block – властивість, яка дозволяє отримати доступ до останнього елементу ланцюга. Ми використовували її в методі create_block_from_transaction.

Давайте перевіримо цей блокчейн.

# main.py

import hashlib

class GeekCoinBlock:
    ...


class Blockchain:
    ...

t1 = "George sends 3.1 GC to Joe"
t2 = "Joe sends 2.5 GC to Adam"
t3 = "Adam sends 1.2 GC to Bob"
t4 = "Bob sends 0.5 GC to Charlie"
t5 = "Charlie sends 0.2 GC to David"
t6 = "David sends 0.1 GC to Eric"

myblockchain = Blockchain()

myblockchain.create_block_from_transaction([t1, t2])
myblockchain.create_block_from_transaction([t3, t4])
myblockchain.create_block_from_transaction([t5, t6])

myblockchain.display_chain()

Тепер запустіть файл main.py.

Data 1: Genesis Block - 0
Hash 1: 39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e

Data 2: George sends 3.1 GC to Joe - Joe sends 2.5 GC to Adam - 39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e
Hash 2: 98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5

Data 3: Adam sends 1.2 GC to Bob - Bob sends 0.5 GC to Charlie - 98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5
Hash 3: 6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589

Data 4: Charlie sends 0.2 GC to David - David sends 0.1 GC to Eric - 6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589
Hash 4: 869df2f03c9860767d35b30a46233fbeea89a3000ae5019d1491e3829d1ab929

Вітаю! 🙌 Ви щойно створили простий блокчейн на Python з нуля.

Тепер ви можете посилити незмінність блокчейну, використовуючи геттери і сеттери, а також реалізувати інші функції, такі як підтвердження роботи, майнінг або будь-яку іншу концепцію, яку ми пояснювали у статті про основи майнінгу біткоїнів.

Висновок

Блокчейн – це технологія, на якій базується біткоїн, ефіріум та будь-яка інша криптовалюта. У цій статті ви навчилися створювати блокчейн на Python, використовуючи алгоритми хешування, такі як sha256, класи та об’єкти.

Ваше завдання – створити систему майнінгу, а чому б і ні, реалізувати її за допомогою REST API, використовуючи такі фреймворки, як Django або Flask.

Багато людей заробляють статки на криптовалютах. Тільки уявіть, що ви можете зробити, якщо створите її самостійно. 🤑

Продовжуйте кодувати! 👨‍💻