Jak stworzyć Blockchain w Pythonie?

Czy wiesz, że Bitcoin jest zbudowany na Blockchain? Dzisiaj zbudujemy Blockchain w Pythonie od podstaw.

Co to jest Blockchain?

W 2008 roku Papier Bitcoin została opublikowana przez nieznaną osobę lub grupę o imieniu Satoshi Nakamoto. Bitcoin wyszedł jako peer-to-peer wersja elektronicznej gotówki, która umożliwiała transakcje bez przechodzenia przez scentralizowane instytucje (banki). Większość ludzi nie wie, że w tym samym artykule Satoshi zdefiniował rozproszony sposób przechowywania informacji, obecnie znany jako Blockchain.

Technologia Blockchain

Mówiąc prościej, Blockchain to wspólna, niezmienna cyfrowa księga, która przechowuje transakcje w zdecentralizowanej sieci komputerów.

Blockchain możemy podzielić na dwa proste pojęcia:

  • Blok: Przestrzeń, w której przechowujemy transakcje
  • Łańcuch: zestaw połączonych rekordów

To definiuje Blockchain jako łańcuch połączonych bloków, w którym każdy blok przechowuje transakcję dokonaną z określonymi parametrami.

Każdy blok jest budowany na innym bloku, tworząc nieodwracalny łańcuch bloków. Innymi słowy, każdy blok zależy od innego. Okazuje się to solidnym i niezmiennym systemem, w którym każdy, kto ma odpowiednie uprawnienia, może sprawdzić integralność.

Blockchain wprowadza ciekawy zestaw funkcji:

  • Niezmienność historii
  • Trwałość informacji
  • Brak błędów w przechowywanych danych

Wiele systemów opiera się obecnie na Blockchain, takich jak kryptowaluty, transfer aktywów (NFT), a być może w najbliższej przyszłości głosowanie.

Warto wspomnieć, że Blockchain w Pythonie nie musi być złożonym programem z tysiącami linii kodu. W swej istocie byłaby to lista powiązanych ze sobą transakcji.

Oczywiście było to krótkie wyjaśnienie, ale jeśli chcesz mieć pełny przewodnik, przygotowaliśmy kompletny samouczek dotyczący Blockchain dla początkujących. Upewnij się, aby to sprawdzić.

Bez dalszej zwłoki zbudujmy prosty Blockchain za pomocą Pythona.

Budowanie łańcucha bloków za pomocą Pythona

Zanim zaczniemy, zdefiniujmy, co będziemy robić w tym samouczku:

  • Zbuduj prosty system Blockchain napisany w Pythonie
  • Skorzystaj z naszego Blockchaina z wcześniej ustalonymi transakcjami reprezentowanymi jako ciągi
  • Przetestuj niezmienność naszego Blockchain

Nie będziemy używać JSON, ale list Pythona. Pozwoli nam to uprościć proces i skupić się na zastosowaniu kluczowych koncepcji łańcucha bloków.

Czego będziesz potrzebować, aby wykonać ten samouczek:

Tworzenie klasy Block

Otwórz swój ulubiony edytor kodu i utwórz plik main.py. To będzie plik, z którym będziemy pracować.

Teraz importuj hashlib, moduł, który pozwala nam tworzyć wiadomości zaszyfrowane jednokierunkowo. Techniki kryptograficzne, takie jak hashowanie, sprawiają, że Blockchain tworzy bezpieczne transakcje.

Funkcja mieszająca to algorytm, który pobiera pewne dane (zwykle zakodowany ciąg) i zwraca unikalny identyfikator, często nazywany „podsumowaniem” lub „sygnaturą”. Ta ostatnia część jest niezbędna; z funkcją mieszającą niewielka różnica w danych wejściowych daje radykalnie inny identyfikator jako dane wyjściowe. Zobaczymy to w akcji później.

Na razie wystarczy zaimportować wbudowany moduł hashlib:

# main.py file
"""
A simple Blockchain in Python
"""

import hashlib

Ten moduł zawiera większość algorytmów mieszających, których będziesz potrzebować. Pamiętaj tylko, że będziemy używać funkcji hashlib.sha256().

Przejdźmy teraz do GeekCoinBlock, naszej całkowicie oryginalnej nazwy blockchain.

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

Wiem, że może to spowodować niezgrabny kawałek kodu. Podzielmy każdą część w następnej sekcji.

Wyjaśnienie GeekCoinBlock

Najpierw tworzymy klasę o nazwie GeekCoinBlock, wrapper dla obiektów, które będą miały określone cechy (atrybuty) i zachowania (metody).

Następnie definiujemy metodę __init__ (nazywaną również konstruktorem), która jest wywoływana za każdym razem, gdy tworzony jest obiekt GeekCoinBlock.

Ta metoda ma trzy parametry:

  • self (instancja każdego obiektu)
  • previous_block_hash (odniesienie do poprzedniego bloku)
  • transaction_list (lista transakcji wykonanych w bieżącym bloku).

Przechowujemy poprzedni hash i listę transakcji oraz tworzymy zmienną instancji block_data jako ciąg. Nie dzieje się tak w przypadku prawdziwych kryptowalut, w których przechowujemy tego rodzaju dane jako kolejny skrót, ale dla uproszczenia będziemy przechowywać każdy blok danych jako ciąg.

Na koniec tworzymy block_hash, którego inne bloki będą używać do kontynuowania łańcucha. Tutaj przydaje się hashlib; zamiast tworzyć niestandardową funkcję skrótu, możemy użyć gotowego sha256 do tworzenia niezmiennych bloków.

Ta funkcja odbiera zakodowane ciągi (lub bajty) jako parametry. Dlatego używamy metody block_data.encode(). Następnie wywołujemy hexdigest(), aby zwrócić zakodowane dane w formacie szesnastkowym.

Wiem, że to wszystko może być przytłaczające, więc pobawmy się hashlib na powłoce Pythona.

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'

Jak widać, niewielka zmiana danych wejściowych, takich jak „Python jest świetny” na „Python nie jest świetny”, może dać zupełnie inny skrót. Ma to wszystko wspólnego z integralnością Blockchain. Jeśli wprowadzisz niewielką zmianę do łańcucha bloków, jego hash zmieni się dramatycznie. To jest powód, dla którego powiedzenie „Nie możesz zepsuć łańcucha bloków” jest prawdziwe.

Korzystanie z naszej klasy bloku

Później zbudujemy całą klasę Blockchain, ale na razie użyjmy naszej klasy Block, aby utworzyć łańcuch bloków (Blockchain).

W tym samym pliku utwórz kilka transakcji składających się z prostych ciągów przechowywanych w zmiennych, na przykład:

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"

Oczywiście GC odnosi się do GeekCoin

Teraz zbuduj pierwszy blok naszego Blockchaina za pomocą klasy GeekCoinBlock i wydrukuj jego atrybuty. Weź pod uwagę, że parametr previous_hash bloku genesis (pierwszy blok poprzedzający inne bloki) zawsze będzie jakimś dowolnym ciągiem lub hashem, w tym przypadku „firstblock”.

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

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

Następnie robimy to samo z drugim blokiem, ale przekazujemy hash pierwszego bloku jako argument 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}")

Uruchommy i przeanalizujmy dane wyjściowe, które otrzymujemy z tego fragmentu kodu. Jeszcze raz wpisz swój terminal:

❯ 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

Na razie widzisz tylko tekst i jakieś 64-znakowe skróty, ale to w zasadzie wznawia mechanizm Blockchain.

Zaczynasz od bloku genezy, podstawy wszystkich innych bloków.

Każdy może zweryfikować integralność łańcucha i właśnie dlatego Blockchain jest tak bezpiecznym systemem. Na przykład, jeśli nieznacznie modyfikujemy treść transakcji, powiedzmy:

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

Widzimy dramatyczną zmianę w haszu bloków.

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

Możesz zobaczyć na tym aktualny projekt Repozytorium GitHub.

Kodowanie łańcucha bloków

Opieranie integralności systemu na ręcznie zakodowanych zmiennych nie jest takie mądre, więc potrzebujemy innego podejścia.

Mamy bloki. Czas zbudować klasę, która połączy je w Blockchain.

Zacznijmy od usunięcia naszych poprzednich transakcji i bloków obiektów, a następnie użyj poniższego kodu.

# 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]

To znowu ogromny kawałek kodu. Rozłóżmy każdą część:

  • self.chain — Lista, na której zapisywane są wszystkie bloki. Dostęp do każdego bloku możemy uzyskać za pomocą indeksów list.
  • generate_genesis_block — Dołącz genezę lub pierwszy blok do łańcucha. Poprzedni hash bloku to „0”, a lista transakcji to po prostu „Genesis Block”.
  • create_block_from_transaction — Pozwala nam dołączyć do łańcucha bloki zawierające tylko listę transakcji. Byłoby bardzo denerwujące ręczne tworzenie bloku za każdym razem, gdy chcemy zarejestrować transakcję
  • display_chain — Wyświetla łańcuch bloków z pętlą for
  • last_block — Właściwość, która umożliwia nam dostęp do ostatniego elementu łańcucha. Użyliśmy go w metodzie create_block_from_transaction.

Przetestujmy ten Blockchain.

# 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()

Teraz uruchom plik 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

Gratulacje! 🙌 Właśnie stworzyłeś od podstaw prosty łańcuch bloków w Pythonie.

Możesz teraz wzmocnić niezmienność Blockchain, używając getterów i seterów oraz zaimplementować inne funkcje, takie jak dowód pracy, wydobywanie lub jakakolwiek inna koncepcja, którą wyjaśniliśmy w artykule o podstawach kopania bitcoinów.

Wniosek

Blockchain to technologia stojąca za Bitcoinem, Etherium i każdą inną kryptowalutą. W tym artykule dowiedziałeś się, jak stworzyć Blockchain za pomocą Pythona, używając algorytmów mieszających, takich jak sha256, klasy i obiekty.

Twoim wyzwaniem jest stworzenie systemu wydobywczego i dlaczego nie, zaimplementowanie go za pomocą REST API przy użyciu frameworków takich jak Django lub Flask.

Wiele osób zarabia fortuny na kryptowalutach. Po prostu wyobraź sobie, co mógłbyś zrobić, gdybyś sam go stworzył.

Kontynuuj kodowanie! 👨‍💻