Pojedynek z inteligentnymi kontraktami: Hyperledger Fabric vs MultiChain vs Ethereum vs Corda

Węzeł źródłowy: 1585333

Istnieje więcej niż jeden sposób umieszczenia kodu w łańcuchu bloków

W większości dyskusji na temat łańcuchów bloków pojawia się pojęcie „inteligentnych kontraktów”. W powszechnej wyobraźni inteligentne kontrakty automatyzują wykonywanie interakcji między stronami, bez konieczności korzystania z zaufanego pośrednika. Wyrażając stosunki prawne kodem, a nie słowami, obiecują umożliwić dokonywanie transakcji bezpośrednio i bez błędów, celowo lub nie.

Z technicznego punktu widzenia inteligentny kontrakt jest czymś bardziej konkretnym: kodem komputerowym, który żyje w łańcuchu bloków i określa zasady transakcji w tym łańcuchu. Ten opis brzmi dość prosto, ale za nim kryje się wiele różnic w sposobie wyrażania, wykonywania i potwierdzania tych reguł. Wybierając platformę blockchain dla nowej aplikacji, pojawia się pytanie „Czy ta platforma obsługuje inteligentne kontrakty?” nie jest właściwym pytaniem. Zamiast tego musimy zapytać: „Jakie rodzaje inteligentnych kontraktów obsługuje ta platforma?”

W tym artykule moim celem jest zbadanie niektórych głównych różnic między podejściami do inteligentnych kontraktów a reprezentowanymi przez nie kompromisami. Zrobię to, patrząc na cztery popularne platformy blockchain dla przedsiębiorstw, które obsługują jakąś formę dostosowanego kodu łańcuchowego. Po pierwsze, IBM Tkanina Hyperledger, który nazywa swoje umowy „kodem łańcucha”. Po drugie, nasza platforma MultiChain, która wprowadza inteligentne filtry w wersji 2.0. Trzeci, Ethereum (i jest dozwolone Kworum i Nora spin-offy), które spopularyzowały nazwę „inteligentny kontrakt”. I w końcu, R3 Corda, który w swoich transakcjach odnosi się do „umów”. Pomimo całej różnej terminologii, ostatecznie wszystkie odnoszą się do tego samego - kodu specyficznego dla aplikacji, który definiuje reguły łańcucha.

Zanim przejdę dalej, powinienem ostrzec czytelnika, że ​​znaczna część poniższej treści ma charakter techniczny i zakłada pewną znajomość ogólnych pojęć związanych z programowaniem i bazami danych. Na dobre lub na złe nie można tego uniknąć - bez zagłębiania się w szczegóły niemożliwe jest podjęcie świadomej decyzji, czy użyć łańcucha blokowego do konkretnego projektu, a (jeśli tak) odpowiedniego rodzaju łańcucha blokowego.

Podstawy Blockchain

Zacznijmy od kontekstu. Wyobraź sobie aplikację, która jest współużytkowana przez wiele organizacji i jest oparta na bazowej bazie danych. W tradycyjnej scentralizowanej architekturze ta baza danych jest hostowana i administrowana przez jeden podmiot, któremu ufają wszyscy uczestnicy, nawet jeśli nie ufają sobie nawzajem. Transakcje modyfikujące bazę danych są inicjowane tylko przez aplikacje w systemach tej centralnej strony, często w odpowiedzi na komunikaty otrzymywane od uczestników. Baza danych po prostu robi to, co jej każą, ponieważ aplikacja ma niejawne zaufanie, że wysyła jej tylko transakcje, które mają sens.

Łańcuchy bloków zapewniają alternatywny sposób zarządzania współdzieloną bazą danych bez zaufanego pośrednika. W łańcuchu bloków każdy uczestnik uruchamia „węzeł”, który przechowuje kopię bazy danych i niezależnie przetwarza transakcje, które ją modyfikują. Uczestnicy identyfikowani są za pomocą kluczy publicznych lub „adresów”, z których każdy ma odpowiadający mu klucz prywatny znany tylko właścicielowi tożsamości. Chociaż transakcje mogą być tworzone przez dowolny węzeł, są one „podpisane cyfrowo” kluczem prywatnym ich inicjatora w celu udowodnienia ich pochodzenia.

Węzły łączą się ze sobą na zasadzie peer-to-peer, szybko propagując transakcje i „bloki”, w których są oznaczone znacznikiem czasu i potwierdzane w sieci. Sam łańcuch bloków jest dosłownie łańcuchem tych bloków, który tworzy uporządkowany dziennik każdej historycznej transakcji. Zastosowano „algorytm konsensusu”, aby zapewnić, że wszystkie węzły osiągną porozumienie co do zawartości łańcucha bloków, bez konieczności scentralizowanej kontroli. (Zauważ, że część tego opisu nie dotyczy Corda, w którym każdy węzeł ma tylko częściową kopię bazy danych i nie ma globalnego łańcucha bloków. Porozmawiamy o tym później).

Zasadniczo każda aplikacja współdzielonej bazy danych może być zaprojektowana przy użyciu łańcucha blokowego w jej rdzeniu. Jednak takie postępowanie stwarza szereg wyzwań technicznych, które nie istnieją w scentralizowanym scenariuszu:

  • Zasady transakcji. Jeśli jakikolwiek uczestnik może bezpośrednio zmienić bazę danych, w jaki sposób upewnimy się, że przestrzega zasad aplikacji? Co powstrzymuje jednego użytkownika przed uszkodzeniem zawartości bazy danych w samolubny sposób?
  • Determinizm. Po zdefiniowaniu tych reguł będą one wielokrotnie stosowane przez wiele węzłów podczas przetwarzania transakcji dla ich własnej kopii bazy danych. W jaki sposób możemy zapewnić, że każdy węzeł uzyska dokładnie ten sam wynik?
  • Zapobieganie konfliktom. Bez centralnej koordynacji, jak radzimy sobie z dwiema transakcjami, z których każda jest zgodna z regułami aplikacji, ale mimo to jest ze sobą sprzeczna? Konflikty mogą wynikać z celowej próby oszukania systemu lub być niewinnym wynikiem pecha i wyczucia czasu.

Skąd więc pochodzą inteligentne kontrakty, inteligentne filtry i kod łańcucha? Ich głównym celem jest praca z podstawową infrastrukturą łańcucha bloków w celu rozwiązania tych problemów. Inteligentne kontrakty są zdecentralizowanym odpowiednikiem kodu aplikacji - zamiast działać w jednym centralnym miejscu, działają na wielu węzłach w łańcuchu bloków, tworząc lub weryfikując transakcje, które modyfikują zawartość tej bazy danych.

Zacznijmy od reguł transakcji, pierwszego z tych wyzwań, i zobaczmy, jak są one wyrażone odpowiednio w Fabric, MultiChain, Ethereum i Corda.

Zasady transakcji

Reguły transakcji pełnią określoną funkcję w bazach danych opartych na blockchain - ograniczając przemiany które można wykonać na stanie tej bazy danych. Jest to konieczne, ponieważ transakcje w łańcuchu bloków mogą być inicjowane przez dowolnego z jego uczestników, a ci uczestnicy nie ufają sobie na tyle, aby pozwolić im dowolnie modyfikować bazę danych.

Zobaczmy dwa przykłady, dlaczego potrzebne są reguły transakcji. Najpierw wyobraź sobie łańcuch bloków przeznaczony do agregowania i oznaczania czasu dokumentów PDF, które są publikowane przez jego uczestników. W takim przypadku nikt nie powinien mieć prawa do usuwania lub zmiany dokumentów, ponieważ podważyłoby to cały cel systemu - trwałość dokumentów. Po drugie, rozważ blockchain reprezentujący wspólną księgę finansową, która śledzi salda swoich użytkowników. Nie możemy pozwolić uczestnikowi na samowolne zawyżenie własnego salda lub zabranie innym pieniędzy.

Wejścia i wyjścia

Nasze platformy blockchain opierają się na dwóch szerokich podejściach do wyrażania reguł transakcji. Pierwszy, który nazywam „modelem wejścia-wyjścia”, jest używany w MultiChain i Corda. Tutaj transakcje wyraźnie wymieniają wiersze bazy danych lub „stany”, które usuwają i tworzą, tworząc odpowiednio zestaw „danych wejściowych” i „wyników”. Modyfikacja wiersza jest wyrażana jako równoważna operacja usunięcia tego wiersza i utworzenia nowego w jego miejsce.

Ponieważ wiersze bazy danych są usuwane tylko w danych wejściowych i tworzone tylko w danych wyjściowych, każde wejście musi „wydawać” dane wyjściowe poprzedniej transakcji. Bieżący stan bazy danych definiuje się jako zbiór „niewykorzystanych danych wyjściowych transakcji” lub „UTXO”, czyli wyjść z poprzednich transakcji, które nie zostały jeszcze wykorzystane. Transakcje mogą również zawierać dodatkowe informacje, zwane „metadanymi”, „poleceniami” lub „załącznikami”, które nie stają się częścią bazy danych, ale pomagają określić ich znaczenie lub cel.

Biorąc pod uwagę te trzy zestawy danych wejściowych, wyjściowych i metadanych, ważność transakcji w MultiChain lub Corda jest definiowana przez kod, który może wykonywać dowolne obliczenia na tych zbiorach. Ten kod może zweryfikować transakcję lub zwrócić błąd z odpowiednim wyjaśnieniem. Możesz myśleć o modelu wejścia-wyjścia jak o zautomatyzowanym „inspektorze” posiadającym listę kontrolną, która zapewnia, że ​​transakcje są zgodne z każdą regułą. Jeśli transakcja nie przejdzie pomyślnie którejkolwiek z tych kontroli, zostanie automatycznie odrzucona przez wszystkie węzły w sieci.

Należy zauważyć, że pomimo wspólnego modelu wejścia-wyjścia, MultiChain i Corda implementują go bardzo różnie. W MultiChain dane wyjściowe mogą zawierać zasoby i / lub dane w formacie JSON, tekstowym lub binarnym. Reguły są zdefiniowane w „filtrach transakcji” lub „filtrach strumieni”, które można ustawić tak, aby sprawdzały wszystkie transakcje lub tylko te, które dotyczą określonych aktywów lub grup danych. Natomiast „stan” wyjścia Corda jest reprezentowany przez obiekt w języku programowania Java lub Kotlin ze zdefiniowanymi polami danych. Reguły Corda są zdefiniowane w „kontraktach”, które są przypisane do określonych stanów, a umowa państwa jest stosowana tylko do transakcji, które zawierają ten stan w swoich wejściach lub wyjściach. Dotyczy to Corda niezwykły model widoczności, w której transakcje mogą być widoczne tylko dla ich kontrahentów lub tych, na których późniejsze transakcje mają wpływ.

Umowy i wiadomości

Drugie podejście, które nazywam „modelem kontraktu - wiadomości”, jest stosowane w Hyperledger Fabric i Ethereum. W tym przypadku w łańcuchu bloków można utworzyć wiele „inteligentnych kontraktów” lub „kodów łańcuchowych”, a każdy z nich ma własną bazę danych i powiązany kod. Baza danych kontraktu może być modyfikowana tylko przez jej kod, a nie bezpośrednio przez transakcje blockchain. Ten wzorzec projektowy jest podobny do „hermetyzacji” kodu i danych w programowaniu obiektowym.

W tym modelu transakcja w łańcuchu bloków rozpoczyna się jako wiadomość wysłana do kontraktu z pewnymi opcjonalnymi parametrami lub danymi. Kod kontraktu jest wykonywany w reakcji na komunikat i parametry i może swobodnie czytać i zapisywać własną bazę danych w ramach tej reakcji. Kontrakty mogą również wysyłać wiadomości do innych umów, ale nie mogą uzyskiwać bezpośredniego dostępu do swoich baz danych. W języku relacyjnych baz danych umowy działają jak egzekwowane „Procedury składowane”, w których cały dostęp do bazy danych odbywa się za pośrednictwem wstępnie zdefiniowanego kodu.

Zarówno Fabric, jak i Quorum, odmiana Ethereum, komplikują ten obraz, umożliwiając sieci definiowanie wielu „kanałów” lub „stanów prywatnych”. Celem jest złagodzenie problemu poufności blockchainów poprzez tworzenie oddzielnych środowisk, z których każde jest widoczne tylko dla określonej podgrupy uczestników. Choć w teorii brzmi to obiecująco, w rzeczywistości umowy i dane w każdym kanale lub państwie prywatnym są odizolowane od tych w pozostałych. W rezultacie pod względem inteligentnych kontraktów środowiska te są równoważne z oddzielnymi łańcuchami bloków.

Przykładowe zasady

Zobaczmy, jak za pomocą tych dwóch modeli zaimplementować reguły transakcji dla księgi finansowej z jednym aktywem. Każdy wiersz w naszej bazie danych księgi zawiera dwie kolumny zawierające adres właściciela i ilość posiadanych aktywów. W modelu przepływów międzygałęziowych transakcje muszą spełniać dwa warunki:

  1. Całkowita ilość aktywów w wynikach transakcji musi odpowiadać sumie w jej danych wejściowych. Zapobiega to przypadkowemu tworzeniu lub usuwaniu pieniędzy przez użytkowników.
  2. Każda transakcja musi być podpisana przez właściciela każdego z jej danych wejściowych. Uniemożliwia to użytkownikom wydawanie swoich pieniędzy bez pozwolenia.

Podsumowując, te dwa warunki są wszystkim, co jest potrzebne do stworzenia prostego, ale realnego systemu finansowego.

W modelu kontrakt-wiadomość umowa na aktywa obsługuje komunikat „wyślij płatność”, który przyjmuje trzy parametry: adres nadawcy, adres odbiorcy oraz ilość do wysłania. W odpowiedzi umowa obejmuje następujące cztery kroki:

  1. Sprawdź, czy transakcja została podpisana przez nadawcę.
  2. Sprawdź, czy nadawca ma wystarczające środki.
  3. Odejmij żądaną ilość z wiersza nadawcy.
  4. Dodaj tę ilość do wiersza odbiorcy.

Jeśli któraś z kontroli w pierwszych dwóch etapach zakończy się niepowodzeniem, umowa zostanie przerwana i nie zostanie dokonana żadna płatność.

Tak więc zarówno model wejścia-wyjścia, jak i model komunikatu umowy są skutecznymi sposobami definiowania reguł transakcji i zapewniania bezpieczeństwa współużytkowanej bazy danych. Rzeczywiście, na poziomie teoretycznym każdy z tych modeli może być użyty do symulacji drugiego. W praktyce jednak najbardziej odpowiedni model będzie zależał od budowanej aplikacji. Czy każda transakcja ma wpływ na kilka czy wiele informacji? Czy musimy być w stanie zagwarantować niezależność transakcji? Czy każda część danych ma wyraźnego właściciela, czy też jest jakiś stan do udostępnienia?

Badanie, w jaki sposób odpowiedzi powinny wpływać na wybór między tymi dwoma modelami, wykracza poza nasz zakres. Ale jako ogólna wskazówka, podczas opracowywania nowej aplikacji blockchain warto spróbować wyrazić jej zasady transakcji w obu formach i zobaczyć, która pasuje bardziej naturalnie. Różnica będzie wyrażać się w następujących kategoriach: (a) łatwość programowania, (b) wymagania dotyczące pamięci i przepustowość oraz (c) szybkość wykrywania konfliktów. Później porozmawiamy o tym ostatnim numerze.

Wbudowane zasady

Jeśli chodzi o zasady transakcji, istnieje jeden sposób, w jaki MultiChain wyraźnie różni się od Fabric, Ethereum i Corda. W przeciwieństwie do tych innych platform, MultiChain ma kilka wbudowanych abstrakcji, które zapewniają podstawowe elementy konstrukcyjne dla aplikacji opartych na łańcuchu bloków, bez wymagające programiści do pisania własnego kodu. Te abstrakcje obejmują trzy obszary, które są powszechnie potrzebne: (a) uprawnienia dynamiczne, (b) aktywa podlegające przeniesieniu oraz (c) przechowywanie danych.

Na przykład MultiChain zarządza uprawnieniami do łączenia się z siecią, wysyłania i odbierania transakcji, tworzenia zasobów lub strumieni lub kontrolowania uprawnień innych użytkowników. Wiele aktywów zamiennych może być emitowanych, przenoszonych, wycofywanych z obrotu lub wymienianych w sposób bezpieczny i atomowy. W łańcuchu można utworzyć dowolną liczbę „strumieni” w celu publikowania, indeksowania i pobierania danych w łańcuchu lub poza łańcuchem w formacie JSON, tekstowym lub binarnym. Wszystkie reguły transakcji dla tych abstrakcji są dostępne po wyjęciu z pudełka.

Podczas tworzenia aplikacji na MultiChain można zignorować tę wbudowaną funkcjonalność i wyrazić reguły transakcji tylko przy użyciu inteligentnych filtrów. Jednak inteligentne filtry są zaprojektowane tak, aby współpracowały z wbudowanymi abstrakcjami, umożliwiając ich domyślne zachowanie ograniczony w spersonalizowany sposób. Na przykład uprawnienia do niektórych działań mogą być kontrolowane przez określonych administratorów, a nie domyślne zachowanie, które musi wykonać każdy administrator. Przeniesienie niektórych aktywów może być ograniczone czasowo lub wymagać dodatkowej zgody powyżej określonej kwoty. Dane w określonym strumieniu można zweryfikować, aby upewnić się, że składają się tylko ze struktur JSON z wymaganymi polami i wartościami.

We wszystkich tych przypadkach inteligentne filtry stwarzają dodatkowe wymagania dotyczące weryfikacji transakcji, ale tego nie robią usunąć proste zasady, które są wbudowane. Może to pomóc w rozwiązaniu jednego z kluczowych wyzwań w aplikacjach blockchain: fakt, że błąd w jakimś łańcuchowym kodzie może prowadzić do katastrofalnych konsekwencji. Widzieliśmy niekończące się przykłady tego problemu w publicznym łańcuchu blokowym Ethereum, najbardziej znanym w Upadek DAO oraz Błędy wielopodpisowe z parzystością. Szersze ankiety znaleźli dużą liczbę typowych luk w inteligentnych kontraktach Ethereum, które umożliwiają atakującym kradzież lub zamrożenie funduszy innych osób.

Oczywiście inteligentne filtry MultiChain mogą również zawierać błędy, ale ich konsekwencje są bardziej ograniczone. Na przykład wbudowane reguły aktywów uniemożliwiają jednemu użytkownikowi wydawanie pieniędzy innego użytkownika lub przypadkowe zarabianie własnych pieniędzy, bez względu na to, jaką inną logikę zawiera inteligentny filtr. Jeśli w inteligentnym filtrze zostanie znaleziony błąd, można go dezaktywować i zastąpić poprawioną wersją, podczas gdy podstawowa integralność księgi jest chroniona. Filozoficznie, MultiChain jest bliższy tradycyjnym architekturom baz danych, w których platforma bazodanowa zapewnia szereg wbudowanych abstrakcji, takich jak kolumny, tabele, indeksy i ograniczenia. Bardziej zaawansowane funkcje, takie jak wyzwalacze i procedury składowane, mogą opcjonalnie zostać zakodowane przez programistów aplikacji w przypadkach, gdy są one rzeczywiście potrzebne.

Zasady transakcji Materiał MultiChain Ethereum Corda
Model Komunikat umowy Wejście wyjście Komunikat umowy Wejście wyjście
Wbudowane żaden Uprawnienia +
aktywa + strumienie
żaden żaden

Determinizm

Przejdźmy do następnej części naszej rozgrywki. Bez względu na to, które podejście wybierzemy, niestandardowe reguły transakcji aplikacji blockchain są wyrażane jako kod komputerowy napisany przez programistów aplikacji. W przeciwieństwie do scentralizowanych aplikacji, ten kod będzie wykonywany więcej niż jeden raz iw więcej niż jednym miejscu dla każdej transakcji. Dzieje się tak, ponieważ wiele węzłów łańcucha bloków należących do różnych uczestników musi zweryfikować i / lub wykonać tę transakcję dla siebie.

To powtarzające się i nadmiarowe wykonanie kodu wprowadza nowy wymóg, który jest rzadko spotykany w scentralizowanych aplikacjach: determinizm. W kontekście obliczeń determinizm oznacza, że ​​fragment kodu zawsze będzie dawał tę samą odpowiedź dla tych samych parametrów, bez względu na to, gdzie i kiedy jest uruchamiany. Jest to absolutnie kluczowe dla kodu, który współdziała z łańcuchem bloków, ponieważ bez determinizmu konsensus między węzłami w tym łańcuchu może się katastrofalnie załamać.

Zobaczmy, jak to wygląda w praktyce, najpierw w modelu przepływów międzygałęziowych. Jeśli dwa węzły mają różne zdanie na temat tego, czy transakcja jest ważna, jeden zaakceptuje blok zawierający tę transakcję, a drugi nie. Ponieważ każdy blok wyraźnie łączy się z poprzednim blokiem, spowoduje to trwałe „rozwidlenie” sieci, w którym jeden lub więcej węzłów od tego momentu nie zaakceptuje opinii większości na temat zawartości całego łańcucha bloków. Węzły w mniejszości zostaną odcięte od ewoluującego stanu bazy danych i nie będą już mogły efektywnie korzystać z aplikacji.

Zobaczmy teraz, co się stanie, jeśli konsensus załamie się w modelu kontrakt-komunikat. Jeśli dwa węzły mają różne zdanie na temat tego, jak kontrakt powinien odpowiedzieć na konkretną wiadomość, może to prowadzić do różnicy w zawartości ich baz danych. To z kolei może wpłynąć na odpowiedź umowy na przyszłe wiadomości, w tym wiadomości, które wysyła do innych umów. Efektem końcowym jest rosnąca rozbieżność między poglądami różnych węzłów na stan bazy danych. (Pole „korzeń stanu” w blokach Ethereum zapewnia, że ​​każda różnica w odpowiedziach kontraktów prowadzi natychmiast do w pełni katastrofalnego rozwidlenia łańcucha bloków, zamiast ryzykować pozostanie w ukryciu przez pewien czas).

Źródła niedeterminizmu

Tak więc niedeterminizm w kodzie blockchain jest wyraźnie problemem. Ale jeśli podstawowe elementy składowe obliczeń, takie jak arytmetyka, są deterministyczne, o co powinniśmy się martwić? Okazuje się, że sporo rzeczy:

  • Najwyraźniej generatory liczb losowych, ponieważ z definicji są zaprojektowane do generowania za każdym razem innego wyniku.
  • Sprawdzanie aktualnego czasu, ponieważ węzły nie będą przetwarzać transakcji dokładnie w tym samym czasie, aw każdym razie ich zegary mogą nie być zsynchronizowane. (Nadal można zaimplementować reguły zależne od czasu, odwołując się do sygnatur czasowych w samym łańcuchu bloków).
  • Wykonywanie zapytań dotyczących zasobów zewnętrznych, takich jak Internet, pliki dyskowe lub inne programy uruchomione na komputerze. Nie można zagwarantować, że zasoby te zawsze będą udzielać tej samej odpowiedzi i mogą stać się niedostępne.
  • Uruchamianie wielu fragmentów kodu w równoległych „wątkach”, ponieważ prowadzi to do „sytuacji wyścigu”, w której nie można przewidzieć kolejności zakończenia tych procesów.
  • Wykonywanie dowolnych obliczeń zmiennoprzecinkowych, które mogą dać nawet bardzo różne odpowiedzi na różnych architekturach procesorów komputerowych.

Nasze cztery platformy blockchain wykorzystują kilka różnych podejść, aby uniknąć tych pułapek.

Deterministyczne wykonanie

Zacznijmy od Ethereum, ponieważ jego podejście jest najbardziej „czyste”. Kontrakty Ethereum są wyrażane w specjalnym formacie zwanym „kodem bajtowym Ethereum”, który jest wykonywany przez maszynę wirtualną Ethereum („EVM”). Programiści nie piszą kodu bajtowego bezpośrednio, ale raczej generują go lub „kompilują” z języka programowania podobnego do JavaScript o nazwie Solidity. (Inne języki były kiedyś dostępne, ale od tego czasu zostały uznane za przestarzałe). Determinizm jest gwarantowany przez fakt, że kod bajtowy Solidity i Ethereum nie może kodować żadnych niedeterministycznych operacji - to takie proste.

Filtry MultiChain i kontrakty Corda wybierają inne podejście, dostosowując istniejące języki programowania i środowiska wykonawcze. MultiChain wykorzystuje JavaScript działający w Google V8 silnik, który również stanowi rdzeń przeglądarki Chrome i platformy Node.js, ale z wyłączonymi źródłami niedeterminizmu. Podobnie Corda używa języka Java lub Kotlin, z których oba są kompilowane do „kodu bajtowego Java”, który jest wykonywany w ramach wirtualnej maszyny języka Java („JVM”). Na razie Corda korzysta ze standardowej niedeterministycznej maszyny JVM firmy Oracle, ale trwają prace nad integracją platformy wersja deterministyczna. W międzyczasie programiści kontraktów Corda muszą uważać, aby nie dopuścić do niedeterminizmu w swoim kodzie.

Jak puryzm Ethereum wypada w porównaniu z ewolucyjnym podejściem przyjętym przez MultiChain i Corda? Główną zaletą Ethereum jest minimalizacja ryzyka - jest mniej prawdopodobne, że zbudowana specjalnie do tego celu maszyna wirtualna zawiera nieumyślne źródło niedeterminizmu. Chociaż takie przeoczenie można naprawić za pomocą aktualizacji oprogramowania, mogłoby to zakłócić działanie każdego łańcucha, który miałby pecha, aby go spotkać. Problem Ethereum polega jednak na tym, że Solidity i EVM stanowią mały i rodzący się ekosystem w szerszym kontekście języków programowania i środowisk wykonawczych. Dla porównania JavaScript i Java to dwa najpopularniejsze języki na Githubdziałają na miliardach urządzeń cyfrowych i mają środowiska wykonawcze, które były optymalizowane przez dziesięciolecia. Przypuszczalnie właśnie dlatego publiczny blockchain Ethereum rozważa przejście na eWASM, deterministyczny rozwidlenie powstającego standardu WebAssembly.

Determinizm przez poparcie

Jeśli chodzi o determinizm, Hyperledger Fabric przyjmuje zupełnie inne podejście. W Fabric, gdy węzeł „klient” chce wysłać wiadomość do jakiegoś kodu łańcucha, najpierw wysyła tę wiadomość do niektórych węzłów „endorser”. Każdy z tych węzłów niezależnie wykonuje kod łańcucha, tworząc opinię o wiadomości efekt w bazie danych tego łańcucha. Opinie te odsyłane są do klienta wraz z podpisem cyfrowym, co stanowi formalne „potwierdzenie”. Jeśli klient otrzyma wystarczającą liczbę rekomendacji dotyczących zamierzonego wyniku, tworzy transakcję zawierającą te adnotacje i rozgłasza ją w celu włączenia do łańcucha.

Aby zagwarantować determinizm, każdy kod łańcucha ma „politykę poparcia”, która dokładnie określa, jaki poziom akceptacji jest wymagany, aby jego transakcje były ważne. Na przykład polityka jednego kodu łańcucha może stanowić, że co najmniej połowa węzłów łańcucha blokowego wymaga potwierdzenia. Inna może wymagać poparcia jednej z trzech zaufanych stron. Tak czy inaczej, każdy węzeł może niezależnie sprawdzić, czy otrzymano niezbędne potwierdzenia.

Aby wyjaśnić różnicę, determinizm w większości platform blockchain opiera się na pytaniu: „Jaki jest wynik uruchomienia tego kodu na tych danych?” - i musimy mieć absolutną pewność, że każdy węzeł odpowie na to pytanie identycznie. Z kolei determinizm w Fabric opiera się na innym pytaniu: „Czy wystarczająca liczba endorserów zgadza się co do wyniku uruchomienia tego kodu na tych danych?” Udzielenie odpowiedzi jest dość prostą kwestią liczenia i nie ma miejsca na wkradanie się niedeterminizm.

Deklaracja determinizmu tkaniny ma wiele interesujących konsekwencji. Po pierwsze, chaincode można napisać w wielu różnych językach programowania, ponieważ nie trzeba ich dostosowywać do determinizmu (obecnie obsługiwane są języki Go, Java i JavaScript). Po drugie, kod łańcucha może być ukryty przed niektórymi uczestnikami łańcucha blokowego, ponieważ musi być wykonany tylko przez klientów i endorserów (sama baza danych jest widoczna na całym świecie). Wreszcie, co najważniejsze, kod łańcucha Fabric może robić rzeczy, które są zabronione w innych środowiskach blockchain, na przykład sprawdzanie pogody za pomocą internetowego interfejsu API online. W najgorszym przypadku, gdy każdy indentator otrzyma inną odpowiedź z tego interfejsu API, klient nie uzyska wystarczającej liczby rekomendacji dla określonego wyniku i żadna transakcja nie zostanie przeprowadzona. (Należy zauważyć, że członkowie zespołu Fabric nadal polecić używając deterministycznej logiki w kodzie łańcucha, aby uniknąć niespodzianek).

Jaką cenę płaci Fabric za tę elastyczność? Jeśli celem blockchain jest usunięcie pośredników ze współdzielonej aplikacji opartej na bazie danych, to poleganie Fabric na endorserach robi duży krok od tego celu. Uczestnikom łańcucha nie wystarczy już przestrzegać zasad kodu łańcucha - potrzebują oni również pewnych innych węzłów, aby się zgodzić, że to zrobili. Co gorsza, złośliwy podzbiór endorserów może zatwierdzać zmiany w bazie danych, które w ogóle nie są zgodne z kodem łańcucha. Daje to endorserom znacznie większą władzę niż walidatorzy w zwykłych łańcuchach bloków, którzy mogą cenzurować transakcje, ale nie mogą naruszać zasad łańcucha blokowego. Twórcy aplikacji Blockchain muszą zdecydować, czy ten kompromis ma sens w ich konkretnym przypadku.

Determinizm Materiał MultiChain Ethereum Corda
Model Potwierdzenia Dostosowane środowisko wykonawcze Maszyna wirtualna zbudowana specjalnie Dostosowane środowisko wykonawcze
Języki Idź + Java + JavaScript JAVASCRIPT Solidność Jawa + Kotlin
Widoczność kodu Kontrahenci +
endorserów
Blockchain Blockchain Kontrahenci +
ludzie
wymuszone Nie Tak Tak Nie na teraz)

Zapobieganie konfliktom

Do tej pory omawialiśmy, w jaki sposób różne platformy blockchain wyrażają reguły transakcji w kodzie i jak deterministycznie zapewniają, że każdy węzeł stosuje te reguły identycznie. Teraz pora porozmawiać o trzecim aspekcie naszej rozgrywki: w jaki sposób każda platforma radzi sobie z możliwością, że dwie transakcje, które są ważne same w sobie, są ze sobą w konflikcie? W najprostszym przykładzie wyobraź sobie, że Alicja ma 10 dolarów w księdze finansowej i transmituje dwie transakcje - jedną wysyłającą 8 USD do Boba, a drugą wysyłającą 7 USD do Charliego. Oczywiście tylko jedna z tych transakcji może się powieść.

Dwa modele

Możemy zacząć od zgrupowania podejścia MultiChain i Corda do tego problemu. Jak opisano wcześniej, w obu przypadkach stosowany jest model przepływów międzygałęziowych do reprezentowania transakcji i ich reguł, w których każdy element wejściowy transakcji zużywa dane wyjściowe poprzedniej transakcji. Prowadzi to do prostej zasady zapobiegania konfliktom: każdy produkt można wydać tylko raz. Filtry MultiChain i umowy Corda mogą polegać na swoich platformach, aby bezwzględnie egzekwować to ograniczenie. Ponieważ 10 dolarów Alicji jest reprezentowane przez wynik poprzedniej transakcji, ta reguła jednorazowego wydatku automatycznie zatrzymuje jej wysyłanie zarówno do Boba, jak i Charliego.

Pomimo tego podobieństwa ważne jest, aby zwrócić uwagę na kluczową różnicę w zapobieganiu konfliktom przez MultiChain i Corda. W MultiChain każdy węzeł widzi każdą transakcję i może niezależnie sprawdzić, czy każde wyjście jest wydawane tylko raz. Każda transakcja, która wykonuje podwójne wydatki w stosunku do wcześniej potwierdzonej transakcji, zostanie natychmiastowo i automatycznie odrzucona. Z kolei w Korda nie ma globalnego łańcucha bloków, więc „notariusze” są zobowiązani do zapobiegania takim podwójnym wydatkom. Każdy stan wyjścia Corda jest przypisany do notariusza, który musi podpisać każdą transakcję wydając dane wyjście, potwierdzając, że nie zostało ono wcześniej wydane. Uczestnicy blockchain muszą ufać notariuszom, że uczciwie przestrzegają tej zasady, a złośliwi notariusze mogą siać spustoszenie do woli. Podobnie jak w przypadku adnotacji w Fabric, ten „jednorazowe wydatki jako usługa”Projekt ma zalety pod względem poufności, ale ponownie wprowadza pośredników, idąc wbrew ziarnu łańcucha bloków. (Ważne jest, aby wyjaśnić, że notariusze Corda mogą być prowadzeni przez grupy uczestników przy użyciu algorytmu konsensusu, więc integralność księgi może być nadal chroniona przed indywidualnymi złymi aktorami).

Przejdźmy do Ethereum. Przypominam, że Ethereum używa kontraktów i komunikatów, a nie danych wejściowych i wyjściowych. W rezultacie konflikty transakcji, takie jak dwie płatności Alicji, nie są natychmiast widoczne dla silnika blockchain. Zamiast tego są wykrywane i blokowane przez umowa który przetwarza transakcje, po potwierdzeniu ich zamówienia w łańcuchu. Podczas przetwarzania każdej płatności Alicji umowa weryfikuje, czy jej saldo jest wystarczające. Jeśli transakcja z płatnością 8 USD na rzecz Boba nastąpi jako pierwsza, zostanie przetworzona w zwykły sposób, pozostawiając Alicji 2 USD na swoim koncie. W rezultacie, gdy kontrakt przetwarza drugą transakcję, płacąc Charliemu 7 dolarów, widzi, że Alice brakuje niezbędnych środków i transakcja zostaje przerwana.

Produkcja a kontrakty

Do tej pory widzieliśmy dwie różne techniki zapobiegania sprzecznym transakcjom - pojedyncze wydatki w MultiChain i Corda oraz weryfikacja na podstawie umowy w Ethereum. Więc co jest lepsze?

Aby pomóc odpowiedzieć na to pytanie, rozważmy przykład konta „1 z 2 multisignature”, na którym znajduje się 100 $ w imieniu Gavina i Helen i które pozwala każdemu z nich na samodzielne wydawanie tych pieniędzy. Gavin nakazuje aplikacji zapłacić Donnie 80 dolarów, a kilka sekund później Helen chce wysłać 40 dolarów Edwardowi. Ponieważ nie ma wystarczających środków na obie płatności, transakcje te nieuchronnie powodowałyby konflikt. W przypadku, gdy obie transakcje są transmitowane, wynik zostanie określony w zależności od tego, która z nich wejdzie jako pierwsza do łańcucha. Zauważ, że w przeciwieństwie do przykładu Alice, ten konflikt jest przypadkowo, ponieważ nikt nie próbuje łamać zasad aplikacji - po prostu mieli pechowy moment.

Biorąc pod uwagę prawdopodobieństwo wystąpienia tego konfliktu, kluczowe pytanie brzmi: po wysłaniu przez Gavina swojej transakcji, po jakim czasie węzeł Heleny dowie się, że jej płatność może się nie powieść? Im krótszy jest ten okres, tym bardziej prawdopodobne jest, że Helena zostanie powstrzymana przed próbą dokonania płatności, co uchroni ją i jej podanie przed kolejną niespodzianką.

W modelu wejścia-wyjścia każdy konflikt między transakcjami jest bezpośrednio widoczny dla platformy blockchain, ponieważ dwie transakcje będą jawnie próbowały wydać ten sam poprzedni wynik. W MultiChain dzieje się tak, gdy tylko transakcja Gavina zostanie propagowana do węzła Helen, zwykle w ciągu sekundy lub mniej. W Corda notariusz odrzuci prośbę o podpisanie transakcji Helen, ponieważ podpisała już transakcję Gavina, więc Helen od razu będzie wiedziała, że ​​jej płatność się nie powiedzie. (Chociaż jeśli sam notariusz Corda jest dystrybuowany, może czekać kilka sekund na odpowiedź). Tak czy inaczej, nie ma potrzeby czekać na potwierdzenie i zamówienie transakcji w łańcuchu bloków.

A co z modelem Ethereum? W takim przypadku platforma blockchain nie ma natychmiastowego sposobu, aby wiedzieć, że wystąpi konflikt. Chociaż węzeł Helen może zobaczyć transakcję Gavina w sieci, nie może wiedzieć, jak wpłynie to na własną transakcję Helen, ponieważ z jego perspektywy są to po prostu dwie wiadomości wysyłane do tej samej umowy. Być może dziesięć sekund później, gdy ostateczna kolejność sprzecznych transakcji zostanie potwierdzona w łańcuchu bloków, węzeł Helen przeliczy rzeczywisty zamiast oczekiwanego wynik, a jej aplikacja odpowiednio zaktualizuje swój wyświetlacz. W międzyczasie zarówno Gavin, jak i Helen pozostaną w ciemności.

Ale nie powinniśmy z tego wyciągać wniosku, że model wejścia-wyjścia zawsze działa najlepiej. Rozważmy odmianę naszego przykładowego scenariusza, w którym Gavin i Helen żądają mniejszych płatności w wysokości 40 USD z pierwotnego salda 100 USD, dokładnie w tym samym czasie. W modelu przepływów międzygałęziowych te transakcje byłyby ze sobą sprzeczne, ponieważ obie wydają ten sam wiersz bazy danych zawierający te 100 USD, a tylko jedna płatność zakończyłaby się powodzeniem. Ale w Ethereum obie transakcje zostałyby pomyślnie przetworzone, niezależnie od ich ostatecznego zamówienia, ponieważ konto zawiera wystarczające środki dla obu. W tym przypadku Ethereum bardziej wiernie spełnia intencje Gavina i Helen.

Zestawy do odczytu i zapisu

Na koniec porozmawiajmy o Fabric, którego podejście oparte na aprobacie jest hybrydą tych dwóch technik. Jak wyjaśniono wcześniej, gdy węzeł „klient” sieci Fabric chce wysłać wiadomość do kontraktu, najpierw prosi niektóre węzły zatwierdzające o wykonanie tej wiadomości w jego imieniu. Węzły zatwierdzające robią to w podobny sposób jak Ethereum - uruchamiając kontrakt w swojej lokalnej bazie danych - ale ten proces jest raczej obserwowany niż natychmiast stosowany. Każdy indosant rejestruje zestaw wierszy, które będą odczytywane i zapisywane, odnotowując również dokładną wersję tych wierszy w danym momencie. Ten „zestaw do odczytu i zapisu” wersjonowanych wierszy jest wyraźnie przywoływany w zatwierdzeniu i zawarty w transakcji, którą rozgłasza klient.

Konflikty między transakcjami Fabric są rozwiązywane po sfinalizowaniu ich zamówienia w łańcuchu. Każdy węzeł niezależnie przetwarza każdą transakcję, sprawdzając zasady zatwierdzania i stosując określone zmiany w bazie danych. Jeśli jednak transakcja odczytuje lub zapisuje wersję wiersza bazy danych, która została już zmodyfikowana przez poprzednią transakcję, ta druga transakcja jest ignorowana. Aby wrócić do sprzecznych płatności Alicji na rzecz Boba i Charliego, obie te transakcje będą odczytywać i modyfikować tę samą wersję wiersza, zawierającą 10 USD, od których Alice zaczęła. Dzięki temu druga transakcja zostanie bezpiecznie i automatycznie przerwana.

Podejście Fabric do rozwiązywania konfliktów działa dobrze, ale pod względem wydajności i elastyczności łączy to, co najgorsze z poprzednich dwóch modeli. Ponieważ adnotacje konwertują transakcje na określone zestawy do odczytu i zapisu, jednoczesne, ale zgodne płatności Gavina i Helen w wysokości 40 USD doprowadziłyby do konfliktu, którego Ethereum unika. Jednak Fabric nie korzysta z przewagi szybkości modelu wejścia-wyjścia, ponieważ endorser wykonują kontrakty z najnowszą wersją bazy danych potwierdzoną przez blockchain, ignorując niepotwierdzone transakcje. Więc jeśli Helen zainicjuje swoją płatność kilka sekund po Gavinie, ale zanim Gavin zostanie potwierdzony w łańcuchu blokowym, Fabric stworzy sprzeczne transakcje, których unika model czysto wejścia-wyjścia.

Zapobieganie konfliktom Materiał MultiChain Ethereum Corda
Model Zestawy do odczytu i zapisu Pojedyncze wydatki Kontrole umów Pojedyncze wydatki
Weryfikacja Niezależny Niezależny Niezależny Zaufani notariusze
Prędkość ~ 10s (potwierdzenie) ~ 1s (propagacja) ~ 10s (potwierdzenie) 0 ~ 5s (notariusz)

Złożony wybór

W tym artykule dokonaliśmy przeglądu wielu różnych sposobów, w jakie Corda, Ethereum, Fabric i MultiChain rozwiązują kluczowe wyzwania związane z „inteligentnymi kontraktami” lub kodem aplikacji osadzonym w łańcuchu bloków. Każda platforma ma różne odpowiedzi na nasze trzy podstawowe pytania: Jak przedstawiane są reguły transakcji? Jak kod jest wykonywany deterministycznie? Jak zapobiegamy konfliktom?

Więc kto jest zwycięzcą naszego starcia z inteligentnymi kontraktami? Powinno być już oczywiste, że nie ma prostej odpowiedzi. Każda platforma stanowi złożony, wielostronny kompromis pomiędzy elastycznością, prostotą, wydajnością, brakiem pośrednictwa, bezpieczeństwem i poufnością. Zatem wybór platformy dla konkretnej aplikacji musi rozpocząć się od szczegółowego zrozumienia modelu zaufania tej aplikacji, typów transakcji, z którymi się ona wiąże, oraz prawdopodobnych wzorców konfliktów. Jeśli znajdziesz kogoś, kto naciska na konkretne rozwiązanie dotyczące inteligentnej umowy, zanim poznają odpowiedzi na te pytania, sugeruję uprzejmie, ale stanowczo nalegać, aby zastosował „inteligentniejsze” podejście.

Prosimy o umieszczanie komentarzy na LinkedIn.

Znak czasu:

Więcej z Multichain