Java i Blockchain – jak to połączyć w aplikacji biznesowej?
Niniejszy artykuł jest kontynuacją tematyki związanej z technologią blockchain, którą rozpoczęliśmy od przedstawienia podstawowych koncepcji samego łańcucha bloków. Idąc dalej, chciałbym pokazać, jak zbudować aplikację wykorzystującą technologię blockchain w Javie, która rozwiązuje realny problem biznesowy.
Robert Witkowski. Senior Software Engineer w ASC LAB. Altkom Software & Consulting należy do polskiej grupy Altkom. W ASC skupiają się osoby lubiące tworzyć rozwiązania technologiczne, jednocześnie spędzając czas razem. Firma najbardziej ceni chęć rozwoju, zaangażowanie oraz podejście do kodowania. Tę organizację tworzą osoby pełne pasji, dlatego odwdzięcza się elastycznym podejściem do pracownika i jego oczekiwań.
Spis treści
Problem biznesowy
Twoja firma się rozrasta, pracuje w niej coraz więcej osób. Do tej pory różnego rodzaju wnioski (o urlop, o nowy sprzęt lub wymianę obecnego) były realizowane w formie papierowej, co często prowadziło do nieakceptowalnych nadużyć i fałszerstw. Poszczególne strony w procesie przestały sobie ufać. Ostatnie spotkanie zarządu zakończyło się decyzją na temat zmiany tego stanu, czyli digitalizacji tych procesów, celem zwiększenia kontroli nad nimi i transparentności. Postanowiono stworzyć do użytku wewnętrznego aplikację, w której będzie można zarządzać wnioskami.
Podstawowe założenia:
- każdy z pracowników może złożyć wniosek,
- pracownik ze specjalnym uprawnieniem może akceptować wnioski,
- każdy wniosek musi zostać zaakceptowany przed dalszym przetwarzaniem,
- wnioski i decyzje muszą być niepodważalne i niezmienialne,
- każdy użytkownik widzi wszystkie wnioski (pełna transparentność).
Przykładowy scenariusz testowy:
- Stwórz “normalnych” użytkowników: user1, user2.
- Stwórz menedżerów: manager1, manager2.
- User1 tworzy wniosek o urlop.
- Manager1 akceptuje wniosek User1 (tworzy pozytywną decyzję).
- User2 tworzy wniosek o urlop.
- Manager2 odrzuca wniosek User2 (tworzy negatywną decyzję).
Dyrektor IT stwierdził, że podstawowe założenia, tj. niepodważalność, niezmienialność, transparentność oraz audytowalność idealnie wpisują się w technologię blockchain. Podjął decyzję, że to właśnie blockchain będzie podstawową bazą danych, jeżeli chodzi o informacje o wnioskach i decyzjach.
Technologie
Chcąc spełnić postawione wymagania biznesowe od razu odrzuciliśmy wszystkie publiczne blockchainy. Dlaczego? Odsyłam Was do naszego poprzedniego artykułu Blockchain-fundamenty, tam staraliśmy się wyjaśnić różnice. Dodatkowo warto spojrzeć na tę prezentację.
Poszukiwania ograniczyliśmy zatem do prywatnych łańcuchów (private blockchain/private DLT). Wniosek z poszukiwań był taki, że najczęściej polecanymi platformami są Hyperledger oraz MultiChain.
Hyperledger jest bardzo mocno wspierany i promowany przez IBM. CEO CEE Karolina Marzantanowicz wspominała na jednym ze spotkań Aula Polska o tym, że firma wdrożyła już ponad 500 projektów opartych o tę platformę. To robi wrażenie.
Po tym spotkaniu byłem (i w sumie wciąż jestem 🙂 ) zafascynowany Hyperledgerem, jednak ostatecznie w naszym projekcie zdecydowaliśmy się użyć platformy MultiChain.
Dlaczego? Głównie dlatego, że w sieci często pojawiają się komentarze mówiące o tym, że łatwiej z nim zacząć, jeżeli zależy nam głównie na time series database. Czy to prawda? Dziś nie jesteśmy w stanie tego stwierdzić, ponieważ nie wykonaliśmy porównania obu technologii “na polu walki”. Mam nadzieję, że uda nam się jeszcze wrócić do tego tematu i sprawdzić Hyperledger w akcji.
Oprócz Multichaina w aplikacji opublikowanej na GitHubie wykorzystaliśmy:
- Java 8 + Spring (Boot, Security) + MultiChainJavaAPI + H2 – backend,
- Angular + Semantic UI – frontend,
- Docker + Kubernetes – konteneryzacja rozwiązania oraz deployment w chmurze.
Poszczególne komponenty systemu
Instalacja MultiChaina
Pierwszym krokiem była oczywiście instalacja MultiChaina na mojej lokalnej maszynie. Bez problemu udało się to zrobić korzystając z poradnika z oficjalnej strony MultiChaina. Nie będę opisywał tutaj dokładnie tego procesu, odsyłam do podlinkowanej instrukcji.
Alternatywnym rozwiązaniem jest uruchomienie wszystkiego za pomocą Dockera, jednym poleceniem, wykorzystując to repozytorium.
Jako, że podlinkowane repozytorium nie było od jakiegoś czasu aktualizowane, postanowiliśmy je skopiować i zaktualizować wersję używanych wewnątrz bibliotek. Polecamy skorzystać zatem z tego, co znajduje się w folderze multichain-cluster w naszym repozytorium.
Uruchamia się to za pomocą Docker Compose. Będąc w folderze ze skryptami w konsoli wystarczy wpisać docker-compose up lub uruchomić run.bat (dla Windowsa) lub run.sh (dla Linuxa).
Utworzony klaster zawiera trzy połączone ze sobą node’y: master node, slave node oraz explorer node.
Uruchomienie docker-compose przez skrypt run.sh
Po kilku minutach całe środowisko MultiChaina wstanie. W konsoli powinny pojawić się logi z explorera:
Teraz można wejść na MultiChain Explorer’a i spojrzeć na pierwszą automatycznie utworzoną transakcję:
MultiChain CLI
Ponieważ nie mieliśmy wcześniej do czynienia z aplikacjami wykorzystującymi MultiChain, postanowiliśmy na początku sprawdzić czy wymyślony przez nas scenariusz uda się zaimplementować z wykorzystaniem CLI. Jaki był tego efekt? Pozytywny, udało się!
Pierwsze kroki zostały dokładnie opisane w README, a plik run.sh w folderze multichain-cli zawiera wszystkie komendy, które należy uruchomić, aby zrealizować kroki scenariusza.
Do implementacji powyższego scenariusza wykorzystane zostały MultiChain Streams. Czym tak naprawdę są te strumienie? Pozwolę sobie zacytować CEO MultiChaina:
Gideon Greenspan
Streams provide a natural abstraction for blockchain use cases which focus on general data retrieval, timestamping and archiving, rather than the transfer of assets between participants. Streams can be used to implement three different types of databases on a chain:
A key-value database or document store, in the style of NoSQL.
A time series database, which focuses on the ordering of entries.
An identity-driven database where entries are classified according to their author.
These can be considered as the ‘what’, ‘when’ and ‘who’ of a shared database.
Potrzebne były nam dwa strumienie. Jeden do przechowywania wniosków, a drugi do przechowywania decyzji. Dzięki takiemu podejściu mogliśmy na poziomie MultiChaina sterować uprawnieniami (kto do jakiego streama może zapisywać), dzięki czemu zwykli użytkownicy nie mogli akceptować wniosków.
MultiChain + Java
Jeżeli chodzi o integrację MultiChaina i Javy skorzystaliśmy z projektu MultiChainJavaAPI. API to jest troszkę ograniczone, ponieważ było tworzone z myślą o zarządzaniu już stworzonym łańcuchem, przez co brakuje w nim metod typu stwórz łańcuch. Założyliśmy, że nasza aplikacja działa na stworzonym inną metodą blockchainie (np. przez CLI), więc te braki nam nie przeszkadzały.
Spójrzmy zatem na pakiety, które ukształtowały nam się w trakcie tworzenia aplikacji:
Co znajduje się w poszczególnych pakietach?
- api – REST Endpoint’y, z których korzysta frontend,
- blockchaindomain – klasy związane z samym blockchainem (nie mające związku z domeną biznesową), dzięki którym w aplikacji można podejrzeć podstawowe informacje o samym łańcuchu i blokach,
- businessdomain – klasy realizujące logikę biznesową aplikacji,
- config – konfiguracja security, CORSa, JSONa,
- init – inicjalizacja bazy in-memory przykładowymi użytkownikami,
- mockchain – zamockowane implementacje interfejsów odpowiedzialnych za działania na blockchainie. Jako, że podczas developmentu nie zawsze chcieliśmy mieć włączonego MultiChaina, stworzone zostały dwa profile aplikacji, którymi możemy sterować za pomocą zmiennej w application.properties
Dzięki adnotacji @Profile nad klasą możemy wskazać Springowi, które Bean’y ma wstrzykiwać w zależności od ustawionego profilu.
Bean MockChainExplorer ma być wstrzyknięty tylko jeśli aplikacja uruchomiona jest z profilem dev.
Bean MultichainExplorer ma być wstrzyknięty tylko jeśli aplikacja uruchomiona jest z profilem innym niż dev:
- multichain – integracja z MultiChainem,
- security – chyba nie trzeba tłumaczyć ,
- shared.primitives – proste klasy opakowujące odpowiedzi serwera do aplikacji klienckiej (ErrorResponse, OkResponse).
Najważniejszym miejscem aplikacji od strony biznesowej jest interfejs Ledger. Interfejs ten jest pewną abstrakcją rejestru wniosków i decyzji (dodawanie/usuwanie/przeglądanie). Na tę chwilę ma on dwie implementacje – jedną bazującą na MultiChainie, a druga to mock, o którym już wspominałem przy okazji omawiania struktury pakietów. Dzięki takiemu podejściu można bardzo łatwo dodawać kolejne implementacje, bazujące np. na Hyperledgerze albo tradycyjnej bazie danych.
Interfejs ten implementowany jest przez klasę MultichainLedger. To właśnie tutaj odbywa się integracja z MultiChainem.
W konstruktorze klasy subskrybujemy się na stworzone streamy lub tworzymy je, jeśli jeszcze nie istnieją. Jak już wspominałem wcześniej, jeden stream służy do przechowywania wniosków (Request), a drugi decyzji (Decision).
Konstruktor klasy MultichainLedger wraz z metodą pomocniczą subscribe
Dodanie czegoś do streama (co odpowiada biznesowej akcji dodania nowej prośby lub decyzji) odbywa się poprzez wykorzystanie metody publishFrom z API MultiChaina. Należy pamiętać, że dane muszą być wcześniej przekonwertowane do postaci HEX.
Tworzenie nowego wniosku
Oprócz tworzenia wniosku/decyzji, niezbędna była funkcjonalność pobierania całej listy lub listy wniosków złożonych przez konkretnego użytkownika. Polega to na wskazaniu strumienia, z którego chcemy pobierać dane i przekonwertowaniu ich z HEXa na nasze obiekty. Przykład poniżej. W przykładzie dane są dodatkowo filtrowane i sortowane.
Frontend – Angular 6
Klient napisany został w Angularze 6 z wykorzystaniem biblioteki Semantic UI.
Aplikacja umożliwia:
- stworzenie nowej prośby i przypisanie jej do swojego menedżera,
- zaakceptowanie lub odrzucenie wniosku (stworzenie decyzji) tylko przez osoby z rolą menedżera,
- obejrzenie listy wniosków,
- obejrzenie listy decyzji,
- obejrzenie listy użytkowników,
- obejrzenie podstawowych informacji o samym łańcuchu bloków i ostatnich transakcjach.
Więcej screenów z samej aplikacji można zobaczyć w README na GitHubie.
Podsumowanie
Stworzenie aplikacji w Javie wykorzystującej blockchain nie jest trudne, jeśli zna się podstawowe założenia dotyczące łańcucha bloków, różnice między wersją publiczną, a prywatną oraz ograniczenia każdej z nich.
Pamiętajmy, że nie wszystkim blockchain jest potrzebny. W naszym poprzednim artykule zamieściliśmy diagram odpowiadający na pytanie Czy potrzebuję blockchaina? Warto się z nim zapoznać i zapamiętać.
Mamy nadzieję, że opublikowana przez nas przykładowa aplikacja będzie pomocna dla każdego, kto chce wejść w ten temat.
Artykuł został pierwotnie opublikowany na asc.altkom.pl. Zdjęcie główne artykułu pochodzi z shellypalmer.com.