fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
7 minut

Budowanie blockchain w 15 minut


17.09.2018

Co to jest technologia blockchain? To pytanie pojawia się coraz częściej w środowisku programistów. Jestem przekonany, że w niedalekiej przyszłości każdy ze środowiska IT zetknie się z tą technologią. Warto więc znać przynajmniej jej podstawy teoretyczne i budowę.

W tym artykule chciałbym przedstawić prostą implementację blockchain w języku C#. Postaram się pokazać, że sama technologia nie jest skomplikowana. Można ją zaimplementować w bardzo prosty sposób w kilkanaście minut, używając kilkudziesięciu linii kodu.

Wprowadzenie

Zastosowanie tej technologii może być skomplikowane, ale sam blockchain nie jest tego powodem. Komplikacje pojawiają się na poziomie bazującego na nim protokołu. Mam tu na myśli różnego rodzaju algorytmy kryptograficzne, metody uzyskiwania konsensusu, sposoby gratyfikacji za utrzymanie sieci, metody tworzenia transakcji, budowę węzłów sieci i ich komunikację między sobą oraz wiele innych elementów składowych kompletnego systemu. Prostotę samej technologii postaram się przedstawić na prostym przykładzie, ponieważ preferuję naukę poprzez wykonywanie, w myśl teorii:

To, co usłyszysz, zapomnisz; to, co zobaczysz, zapamiętasz; to, co zrobisz, zrozumiesz

T. Harv Eker (“Bogaty albo biedny. Po prostu różni mentalnie“)

Teoria

Zanim przejdziemy do implementacji – krótki wstęp teoretyczny. :]

Blockchain

Blockchain, jak sama nazwa wskazuje, to łańcuch bloków, które połączone są między sobą za pomocą kryptografii. W każdym bloku zapisywane są różnego rodzaju dane. Mogą to być np. dane dotyczące transakcji finansowych (obecnie najbardziej popularne), ale ta technologia bardzo szybko się rozwija i mamy już projekty zapisujące inne informacje, choćby dane medyczne, osobowe czy własność intelektualną.

Hasz (hash)

Zanim przejdziemy do implementacji, warto zapoznać się jeszcze z pojęciem hasza. W prostych słowach jest to pewien podpis cyfrowy pakietu danych. Powstaje za pomocą odpowiedniej funkcji (skrótu/haszującej), w której zaimplementowany jest specjalny algorytm. Funkcja ta dla tego samego pakietu danych wejściowych zwraca taki sam wynik – hasz.

Konstrukcja blockchain

W najprostszej wersji minimalistycznej blockchain jest złożony z listy bloków, z których każdy składa się z:

  1. hasza bloku poprzedniego,
  2. listy transakcji,
  3. hasza bloku aktualnego.
Blockchain - prosty diagram

Blockchain – prosty diagram

Implementacja

Na początek przygotowałem swoją funkcję haszującą, która bazuje na algorytmie SHA256:

public static string GetSha256Hash(object obj)
{
    var sha256 = new SHA256Managed();
    var hashBuilder = new StringBuilder();
            
    // zamiana obiektu na tablicę bajtów
    byte[] bytes = ObjectToByteArray(obj);
    // obliczanie hasza
    byte[] hash = sha256.ComputeHash(bytes);
            
    // konwersja tablicy bajtów na łańcuch znaków hexadecymalnych
    foreach (byte x in hash)
        hashBuilder.Append($"{x:x2}");

    return hashBuilder.ToString();
}

Żeby zobrazować, czym jest hasz, utworzyłem dwa obiekty:

string[] test1 = { "a", "b", "c" };
string[] test2 = { "a", "b", "c" };

i wypisałem na konsolę ich hasze za pomocą przedstawionej wcześniej funkcji haszującej:

Console.WriteLine($"Hash 1: {Helper.GetSha256Hash(test1) }");
Console.WriteLine($"Hash 2: {Helper.GetSha256Hash(test2) }");

Dało to wynik:

Hash 1: 3b5777b0a5baf0ef260f46e3228f6cc033d7daecd1ba5240c1c96f40ea07d08d
Hash 2: 3b5777b0a5baf0ef260f46e3228f6cc033d7daecd1ba5240c1c96f40ea07d08d

Następnie zmieniłem wartość jednego z obiektów – dodałem do tablicy dodatkowy element:

string[] test1 = { "a", "b", "c" };
string[] test2 = { "a", "b", "c", "d" };

co dało wynik:

Hash 1: 3b5777b0a5baf0ef260f46e3228f6cc033d7daecd1ba5240c1c96f40ea07d08d
Hash 2: 5b0ec165e91dd27eaf5ae4c59d0ed41c38a4b496073eef0825e5972e4e4ff427

Jak widać, gdy dane mają stałą wartość, hasz jest zawsze taki sam. Jeśli natomiast dane się zmienią, to hasz również będzie inny. Wystarczy zmiana jednego bajtu, by hasz miał zupełnie inną wartość.

Pora przejść do sedna wpisu i zbudować w końcu blockchain. :) Będziemy do tego potrzebowali klasy transakcji:

[Serializable]
public class Transaction
{
    public double Amount { get; set; }
    public string From { get; set; }
    public string To { get; set; }
}

Właściwości klasy transakcji nie mają większego znaczenia – może tam się znaleźć cokolwiek w zależności od tego, co w danym blockchainie będziemy zapisywać. W tym przykładzie zapisujemy transakcje transferu wartości – mamy nadawcę, odbiorcę i ilość, jak w najprostszym scenariuszu transferu środków finansowych. W innych przypadkach struktura klasy mogłaby wyglądać zupełnie inaczej.

Następnie przygotujmy klasę bloku:

[Serializable]
public class Block
{
    public string Hash { get; set; }
    public string PreviousHash { get; set; }
    public List<Transaction> TransactionList { get; set; }
}

Na koniec utwórzmy klasę Blockchain:

public class Blockchain
{
    public List<Block> BlockList { get; set; }
    public Block CurrentBlock { get; set; }
}

Można powiedzieć, że to tylko klasa pomocnicza, bo nie jest ona konieczna.

Wykorzystanie utworzonych klas:

Blockchain blockchain1 = new Blockchain();

blockchain1.AddTransaction(5, "Jan", "Michał");
blockchain1.AddTransaction(2.1, "Grzegorz", "Kamil");
blockchain1.AddTransaction(1.23, "Paweł", "Jakub");

blockchain1.SaveBlock();
Console.WriteLine(blockchain1.CurrentBlock.PreviousHash);
blockchain1.SaveBlock();
Console.WriteLine(blockchain1.CurrentBlock.PreviousHash);

Tworzę obiekt blockchain, do którego dodaję transakcje (dodawane są one do aktualnego bloku). Następnie zapisuję transakcję, co wiąże się z dodaniem aktualnego bloku do łańcucha i utworzeniem nowego, pustego bloku. Wynikiem działania takiego programu będzie wypisanie dwóch haszów poszczególnych bloków w łańcuchu:

3021721be0112ccb3895ffa0372ba1e901db7bed68e89dd6c241cc76e4e8c847
9e9f9dbfab7c1b9efb0e1a645f805536ea81249d8926b714ee5805be737a6e5d

Jedną z głównych cech blockchainu, jaką możemy tutaj zaobserwować, jest jego niezmienialność. Wystarczy, że zmienię jakąkolwiek informację w którejkolwiek transakcji w którymś z bloków, a wszystkie hasze się zaktualizują. Przykład:

zmieniam:

blockchain1.AddTransaction(5, "Jan", "Michał");

na:

blockchain1.AddTransaction(4, "Jan", "Michał");

Wynik działania programu po tej zmianie będzie następujący:

ed71792dc315cecf92b4d6f0459220c94846fcbc224f726b7133c7579e92563f
f95020f748251092b8747681329eefc52a769b69d8581f8aa8efb9274fe45fd4

Modyfikacja jakiejkolwiek transakcji w łańcuchu powoduje zmianę haszów w całym łańcuchu od bloku, w którym modyfikacja transakcji nastąpiła. Jest to więc metoda na zachowanie niezmienności, ponieważ jakiekolwiek zmiany w łańcuchu spowodują niezgodność haszów.

Kompletny kod źródłowy jest dostępny na GitHubie:
https://github.com/plipowczan/MySimpleBlockchain.

Podsumowanie

Cała idea wykorzystania technologii blockchain polega na utrzymaniu niezmienności danych i ich bezpieczeństwie. Na podstawie powyższego przykładu implementacji jesteśmy w stanie zaobserwować, że da się to osiągnąć. Mechanizmy uzyskania niezmienności i bezpieczeństwa są zapewnione przez odpowiednie protokoły. Budowę prostego systemu opartego na takim protokole przedstawię w kolejnym wpisie.

Pytania? Sugestie? Zostaw komentarz!

0 0 votes
Article Rating
18 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Mateusz
5 years ago

Zapowiada się świetny cykl! Jak często planowane są publikacje wpisów?

Piotr Gankiewicz
5 years ago

Cześć,

Dobrze się składa, bo akurat zacząłem zgłębiać tę tematykę i mam następujące pytanie (być może wybiegnę o 1 lub 2 artykuły w przód).

Gdy dochodzimy do PoW i ustalamy pewne difficulty (czyli ilość 0 na początku hasha), w naszym bloku posiadamy nonce, inkrementowany co kolejne obliczenie hasha – dla większej ilości 0 bardzo łatwo go “przekręcić” (mamy tylko int i 32 bity), a nie mogłem się doszukać jednoznacznej odpowiedzi w sieci – jakie inne pole w bloku możemy wtedy zmodyfikować/dodać aby “kopać dalej” – extra nonce, timestamp, coś innego?

Krzysztof "noisy" Szumny

to zależy od konkretnej implementacji blockchaina. Generalnie możesz zmieniać wszystko, co na końcu jest hashowane. By zmienił się hash transakcji, po prostu chcesz wprowadzić zmianę w blocku. Natomiast może to być dowolna zmiana. Najprostszą jest oczywiście zmiana nonce, ale kolejną może być np. zmiana kolejności transakcji. Transakcje najczęściej są podczepione za pomocą merkle-tree do roota. Gdy hash roota się zmieni, to efekt jest ten sam jakby zmienił się nonce.

Zakładając, że trzeba wpakować do blocku transakcje, które są od siebie niezależne, to mając 1000 transakcji, możesz je ułożyć na 1000! ~= 4*10^2567 sposobów… więc możliwych permutacji raczej nigdy nie braknie.

Piotr Gankiewicz
5 years ago

Dzięki, o tym nie pomyślałem. A możesz mi wskazać przykładowe (życiowe) rozwiązania co jest wykorzystane w jakim blockchainie? Przeglądając komentarze po rożnych forach trafiłem np. na “getblocktemplate” ale chciałem wyjść od czegoś możliwie prostego na start.

Pawel Nowosielski
Pawel Nowosielski
5 years ago

@Piotr – myślę, że dobrym, praktycznym rozwiązaniem jest zignorowanie problemu “przekręconego nonce”.
1) jesteś jednym z wielu nodów kopiących dany blok, każdy z nich ma inny zbiór tx i w innej kolejności.
2) “difficulty” nie jest zadane z góry, ale jest funkcją – np. sieć zaczyna akceptować bloki “z mniejszą ilością zer” jeśli od ostatniego bloku minęło ileś czasu.
A więc sprowadza się to do tego, że szansa niewykopania następnego bloku jest coraz miej prawdopodobna

Arek z Bloga Askomputer

Wreszcie ktoś się zabrał na naszej rodzimej ziemi blockchain od strony programistycznej. Mimo iż nie programuje to jednak chętnie będę śledził cykl :)

Kuba
Kuba
5 years ago

Ooo – na coś takiego czekałem! Dzięki!

Kuba
Kuba
5 years ago

Ostatnio coraz bardziej interesuje mnie wykorzystanie blockchaina w biznesie. Sporo czytałem w innych źródłach i trochę brakowało mi tego tematu na devstyle. Trzymam kciuki i z pewnością będę śledził cykl! :-)

Pozdrawiam!

Paweł
Paweł
5 years ago

Świetny artykuł, proste wytłumaczenie, czekam na kolejny wpis :)

Dawid
Dawid
5 years ago

To jak odwrócona linked list’a wygląda. Bardzo fajny artykuł. Dzięki!

Kuba
5 years ago

Dzięki, obowiązkowo całą serię przeczytam z zaciekawieniem :-)

Łukasz Krawczak
Łukasz Krawczak
5 years ago

Ciekaw jestem jakby się to prezentowało w bardziej skomplikowanych projektach. Mimo wszystko będę zaglądał. :)

Michał Białecki
5 years ago

Do pełnego zrozumienia kodu zarakło mi implementacji metody SaveBlock().

Dobry artykół, świetne wprowadzenie. Z chęcią zobaczyłbym jeszcze modyfikację bloku oraz przeliczanie wszystkich hashów. Oczywiście jeżeli byłoby to ok z założeniami blockchain.

Pozycjonowanie
Pozycjonowanie
5 years ago

Fajnie to wyjaśniłeś. Zawsze miałem problem ze zrozumieniem tego :D Pytałem kumpli po fachu to też mi jasno nie potrafili odpowiedzieć. Dzięki fajny artykuł :)

Justyna
5 years ago

Świetny wstęp – można spokojnie załapać ideę za tym stojącą, bez przegrzebywania się przed setki artykułów napakowanych ‘buzzwordami’ :)

Kurs Gita

Zaawansowany frontend

Szkolenie z Testów

Szkolenie z baz danych

Książka

Zobacz również