Skip to main content

Współczesne systemy informatyczne działają na zasadzie jednego, scentralizowanego źródła wszystkich decyzji w systemie, tzw. źródła prawdy (ang. source of truth). Jako czytelnik naszego portalu już pewnie wiesz, że Blockchain jest siecią zdecentralizowaną, co niesie za sobą wiele szans, ale i wyzwań związanych ze skalowalnością.

Niektóre z Blockchainów pozwalają na uruchomienie na nich programów komputerowych, które są wykonywane i weryfikowane przez wszystkich uczestników sieci. Można więc w uproszczeniu uznać je za ogromne, rozproszone komputery, na których wykonują się programy nazywane smart kontraktami.Paradoksalnie, najpopularniejszy z Blockchainów, czyli ten, na którym operuje Bitcoin, nie pozwala na uruchomienie smart kontraktu. Największą siecią oferującą tą funkcjonalność jest Ethereum, dlatego to na niej skupimy się w dalszej częsci wpisu.

Jak podejmowane są decyzje w Ethereum?

Żeby dojść do tego, jak szczegółowo działają smart kontrakty, musimy przejść przez kilka innych elementów architektury systemów, żeby wszystko pod koniec ładnie złożyło nam się w całość.

Konto

Konto w Ethereum jest jednostką (ang. entity), która posiada saldo w Ether (token w Blockchainie Ethereum) i ma możliwość wysyłania transakcji do sieci. Konta i ich salda są przechowywane w wielkiej tabeli i są częścią stanu całej sieci.Konta mogą być własnością użytkownika (externally owned), co oznacza, że każdy, kto ma klucz do konta, ma nad nim kontrolę. Drugim typem kont są te przypisane do smart kontraktu, wtedy są kontrolowane przez jego kod.

Transakcje

Transakcja jest po prostu akcją zainicjowaną przez konto, które jest kontrolowane przez człowieka (externally owned account). Jeżeli Paweł wyśle Markowi 1 ETH, to z konta Pawła znika 1 ETH, a na koncie Marka kwota się pojawia. Taka transakcja jest po prostu zaszyfrowaną instrukcją, która zmienia stan całej sieci, ponieważ każdy z jej węzłów musi być o niej poinformowany.

Zmiana stanu całej sieci poprzez wykonanie jednej transakcji

Ethereum Virtual Machine (EVM)

Wirtualna maszyna Ethereum jest warstwą abstrakcji pomiędzy maszyną a kodem na niej wykonywanym. Inaczej mówiąc jest abstrakcją całego systemu komputerowego, działającego na każdym z węzłów w sieci, a każda operacja wykonana na EVM np. dostęp do pamięci czy cyklów obliczeniowych procesora jest przez sieć mierzona i mierzona jednostką nazwaną gas.

Najczęściej blockchainy są opisywane jako rozproszona księga (distributed ledger), czyli zapis szeregu akcji w wielu miejscach jednocześnie. W przypadku systemów komputerowych jest to rejestr transakcji na wszystkich węzłach sieci. Ethereum pozwala jednak na znacznie więcej. Pozwala na implementację smart kontraktów, więc nie jest po prostu rozproszoną księgą, która trzyma ogromną ilość kont i ich sald.

Ethereum jest rozproszoną maszyną stanów, która trzyma konta, ich salda oraz, co najważniejsze, obecny stan całej sieci, który może zmieniać się wykonując zbiór zaprogramowanych instrukcji.

Opłaty (gas)

Za każdą transakcję w Ethereum trzeba uiścić opłatę (gas fee). Gas jest koncepcją jednostki przedstawiającej nakład mocy obliczeniowej potrzebnej do wykonania danej czynności w sieci.

Opłaty muszą być uiszczane w tokenach ETH, jednak stanowią bardzo małą część całego ETH – więc używa się do nich jednostek gwei (1 gwei = 0.000000001 ETH).

Każda transakcja w sieci Ethereum zużywa pewną ilość gas, ale nie wszystkie transakcje zużywają go tyle samo. Dostęp do pamięci, czy operacje zapisu na dysku mają inną „cenę” za wykonanie niż proste operacje arytmetyczne. Można to porównać do tankowania samochodu przed podróżą, jeżeli chcemy gdziekolwiek pojechać – musimy wydać pieniądze na paliwo. Jeżeli podróż jest długa lub trasa bardziej wymagająca, to samochód zużyje go więcej – analogicznie zachowuje się Blockchain, im bardziej wymagająca i skomplikowana operacja do wykonania, tym wyższy trzeba zapłacić gas fee. Dla przykładu, zwykłe przesłanie środków z jednego konta na drugie kosztuje 21000 jednostek gas, a złożenie zlecenie zakładu na jednej z platform bukmacherskich może kosztować nawet 1000000 gas. Wartości te nazywamy również limitem opłat (gas limit) za daną transakcję i określają maksymalna ilość jednostek gas, które EVM wykona podczas danej operacji. Limit ten zabezpiecza nas przed smart kontraktami w których są błędy np. nieskończona pętla, która zużyłaby nam cały zapas zgromadzonego Ethereum, ponieważ wykona nieskończoną liczbę operacji za które musielibyśmy płacić dopóki nie skończyłyby się środki w naszym portfelu.

Konto, które zamierza wykonać transakcję musi ustawić konkretną cenę, jaką chce zapłacić za jednostkę gas (gas price). Cena ta jest na ogół zasugerowana przez serwisy obliczające optymalną wartość w danym momencie tzw. Oracles.  Całkowita cena jaką użytkownik zapłaci za transakcję wynosi transaciton fee = gas price * gas limit. Przyjrzyjmy się przykładowej transkacji, kiedy Marek chce wysłać Pawłowi 2 ETH, to gas limit wyniesie 21000, a przykładowy gas price to 100 gwei. Całkowita opłata wyniesie:
Gas limit * Gas price = 21000 * 100 = 2100000 gwei lub 0.0021 ETH.

Po niedawnej aktualizacji Ethereum (London Upgrade wykonanej w sierpniu 2021r.) schemat naliczania opłat za transakcję (transaction fees) uległ niewielkiej zmianie. Od niedawna można w swoich transakcjach ustawić również tzw. miner tip, czyli napiwek dla walidatora transakcji, dzięki temu powinna wykonać się ona szybciej. Pojawiły się parametry takie jak base fee i max fee per transaction, co oznacza minimalną i maksymalną kwotę w gwei, jaką jesteśmy gotowi zapłacić za wykonanie jednostki gas w danej transkacji. Base fee jest ustalane przez sieć Ethereum i jest zależna od wolumenu transkacji w konkretnym momencie.

Przykładowo Marek chce odesłać Pawłowi 2 ETH, parametry transakcji są następujące:

Gas limit: 21000
Base fee:  200
Tip:       10

Całkowity koszt transkacji wyniesie więc Gas Limit * (Base Fee + Tip), czyli 21000 * (200 + 10) = 4410000 gwei czyli 0.00441 ETH , co przy dzisiejszym kursie wynosi ok. 13 dolarów amerykańskich. Trochę drogo jak za zwykły przelew 🙂

Transakcje w Ethereum są transparentne i możemy je podejrzeć np na https://etherscan.io/. Przykładowa prawdziwa transakcja, która zawiera parametry omówione wcześniej wygląda następująco:

Przykładowa transakcja w Ethereum. Źródło: etherscan.io

Smart kontrakty

Jak wspomniałem wcześniej, Ethereum, w odróżnieniu od Bitcoina, nie jest po prostu cyfrową walutą. Jest przede wszystkim platformą, na której można wdrażać i wykonywać smart kontrakty, autonomiczny kod źródłowy, który zostanie wykonany przez Ethereum Virtual Machine na węzłach sieci bez udziału zcentralizowanego podmiotu.

Klasycznym, podanym w dokumentacji Ethereum, przykładem smart kontraktu jest kod opisujący działanie automatu z przekąskami, zapoznajmy się z nim. Wysokopoziomowy opis wygląda następująco:

money + snack selection = snack dispensed

Ta logika jest zaprogramowana w większości automatów z przekąskami. Dzięki czemu przy każdym automacie nie musi stać sprzedawca, który liczy pieniądze, wyszukuje odpowiedni numer na półce i wydaje kupującemu towar – wszystko jest zautomatyzowane.

Uproszczona implementacja przypadku smart kontraktu opisującego ten przypadek wygląda tak:

contract VendingMachine {

    address public owner;
    mapping (address => uint) public cupcakeBalances;

    constructor() {
        owner = msg.sender;
        cupcakeBalances[address(this)] = 100;
    }

    function refill(uint amount) public {
        require(msg.sender == owner, "Only the owner can refill.");
        cupcakeBalances[address(this)] += amount;
    }

    function purchase(uint amount) public payable {
        require(msg.value >= amount * 1 ether, "You must pay at least 1 ETH per cupcake");
        require(cupcakeBalances[address(this)] >= amount, "Not enough cupcakes in stock to complete this purchase");
        cupcakeBalances[address(this)] -= amount;
        cupcakeBalances[msg.sender] += amount;
    }
}

Powyzszy smart kontrakt pozwala wykonać transakcję z klientem bez człowieka obsługującego maszynę przy każdej z nich, sprzedaż jest zaprogramowana i odbywa się automatycznie. Przejdźmy przez niego linija po linijce:

address public owner;
mapping (address => uint) public cupcakeBalances;

Deklaracja zmiennych globalnych kontraktu, w których zapisany jest właściciel kontraktu (naszego automatu) oraz stan posiadania przekąsek przez dowolny adres użytkownika kontraktu.

constructor() {
    owner = msg.sender;
    cupcakeBalances[address(this)] = 100;
}

Konstruktor klasy. Ustanawia konto wdrażające kontrakt jego właścicielem i ustawia początkową ilość przekąsek w automacie na 100.

function refill(uint amount) public {
    require(msg.sender == owner, "Only the owner can refill.");
    cupcakeBalances[address(this)] += amount;
}

Implementacja funkcji uzupełniającej stan automatu, jeżeli przekąski zaczną się kończyć. Metoda sprawdza, czy uzupełnienia dokonuje właściciel kontraktu, a następnie zwiększa bilans przekąsek o zadaną ilość.

function purchase(uint amount) public payable {
    require(msg.value >= amount * 1 ether, "You must pay at least 1 ETH per cupcake");
    require(cupcakeBalances[address(this)] >= amount, "Not enough cupcakes in stock to complete this purchase");
    cupcakeBalances[address(this)] -= amount;
    cupcakeBalances[msg.sender] += amount;
}

Najważniejsza część programu, czyli metoda odpowiadająca za zakupy! Najpierw następuje sprawdzenie dwóch warunków:

  1. czy kupujący ma wystarczającą ilość środków, żeby dokonać zakupu
  2. czy w automacie są jeszcze przekąski na sprzedaż

Jeżeli powyższe warunki zostały spełnione, to Ether przechodzi z konta kupującego na konto kontraktu, a kontrakt podbija „stan” przekąsek kupującego o dokonany zakup.

Powyższy przykład jest dosyć trywialny, jednak pokazuje istotę zautomatyzowanego smart kontraktu. Jak wyjaśniliśmy wcześniej, oprócz ceny za przekąskę kupujący musiałby zapłacić również gas fee, które akurat w tym przypadku nie powinno być zbyt wysokie, bo nie zostały tutaj przeprowadzone żadne skomplikowane operacje.

Przyszłość smart kontraktów

Prawdą jest, że smart kontrakty dopiero zaczynają swoją drogę do masowej adopcji. Ogromna większość transakcji w internecie przeprowadzana jest przy użyciu tradycyjnych scentralizowanych systemów, a wszelkie wątpliwości i założenia są raczej zapisane w tradycyjnych umowach i rozstrzygane przez ludzi siedzących przed komputerami.

Jedną za najbardziej obiecujących branż, które mogą zostać zmienione dzięki temu mechanizmowi są ubezpieczenia. Często można usłyszeć o wątpliwościach przy wypłacie odszkodowania, wynikających z różnych interpretacji warunków wypłaty przez ubezpieczonego i ubezpieczającego. Języki programowania wymuszają zapisy precyzyjniejsze niż języki naturalne i dzięki temu takie spory mogłyby zostać rozstrzygane automatycznie.

Teoretycznie każda umowa mogłaby w przyszłości zostać zastąpiona smart kontraktem działającym na Blockchainie, dzięki temu byłaby transparentna i precyzyjna dla każdej ze stron, a wykonanie jej zapisów następowałoby automatycznie. Na szeroką adopcję należy niestety jeszcze poczekać 🙂