Przejdź do głównej treści
Change page

Anatomia inteligentnych kontraktów

Inteligentny kontrakt to program, który działa pod określonym adresem w sieci Ethereum. Składa się z danych i funkcji, które mogą zostać wykonane po otrzymaniu transakcji. Oto przegląd tego, z czego składa się inteligentny kontrakt.

Wymagania wstępne

Upewnij się, że najpierw przeczytałeś o inteligentnych kontraktach. Ten dokument zakłada, że znasz już języki programowania, takie jak JavaScript lub Python.

Dane

Wszelkie dane kontraktu muszą być przypisane do lokalizacji: do storage lub memory. Modyfikacja pamięci (storage) w inteligentnym kontrakcie jest kosztowna, dlatego musisz przemyśleć, gdzie powinny znajdować się Twoje dane.

Pamięć (Storage)

Trwałe dane są określane jako storage i są reprezentowane przez zmienne stanu. Wartości te są trwale przechowywane na blockchainie. Musisz zadeklarować ich typ, aby kontrakt mógł śledzić, ile miejsca na blockchainie będzie potrzebował po skompilowaniu.

// Przykład Solidity
contract SimpleStorage {
    uint storedData; // Zmienna stanu
    // ...
}
# Przykład Vyper
storedData: int128

Jeśli programowałeś już w językach obiektowych, prawdopodobnie znasz większość typów. Jednak address powinien być dla Ciebie nowością, jeśli dopiero zaczynasz programować na Ethereum.

Typ address może przechowywać adres Ethereum, co odpowiada 20 bajtom lub 160 bitom. Zwraca on wartość w notacji szesnastkowej z wiodącym 0x.

Inne typy to m.in.:

  • wartości logiczne (boolean)
  • liczby całkowite (integer)
  • liczby stałoprzecinkowe
  • tablice bajtów o stałym rozmiarze
  • tablice bajtów o dynamicznym rozmiarze
  • literały wymierne i całkowite
  • literały łańcuchowe (string)
  • literały szesnastkowe
  • typy wyliczeniowe (enum)

Aby uzyskać więcej wyjaśnień, zapoznaj się z dokumentacją:

Pamięć (Memory)

Wartości, które są przechowywane tylko przez czas wykonywania funkcji kontraktu, nazywane są zmiennymi w pamięci (memory). Ponieważ nie są one trwale przechowywane na blockchainie, ich użycie jest znacznie tańsze.

Dowiedz się więcej o tym, jak EVM przechowuje dane (Storage, Memory i Stack) w dokumentacji Solidity (opens in a new tab).

Zmienne środowiskowe

Oprócz zmiennych zdefiniowanych w kontrakcie istnieją pewne specjalne zmienne globalne. Służą one głównie do dostarczania informacji o blockchainie lub bieżącej transakcji.

Przykłady:

WłaściwośćZmienna stanuOpis
block.timestampuint256Znacznik czasu (timestamp) epoki bieżącego bloku
msg.senderaddressNadawca wiadomości (bieżącego wywołania)

Funkcje

W najprostszych słowach, funkcje mogą pobierać lub ustawiać informacje w odpowiedzi na przychodzące transakcje.

Istnieją dwa rodzaje wywołań funkcji:

  • internal – nie tworzą one wywołania EVM
    • Funkcje wewnętrzne i zmienne stanu mogą być dostępne tylko wewnętrznie (tj. z poziomu bieżącego kontraktu lub kontraktów z niego dziedziczących)
  • external – tworzą one wywołanie EVM
    • Funkcje zewnętrzne są częścią interfejsu kontraktu, co oznacza, że mogą być wywoływane z innych kontraktów oraz za pośrednictwem transakcji. Zewnętrzna funkcja f nie może być wywołana wewnętrznie (tj. f() nie zadziała, ale this.f() zadziała).

Mogą być również public lub private

  • Funkcje public mogą być wywoływane wewnętrznie z poziomu kontraktu lub zewnętrznie za pośrednictwem wiadomości
  • Funkcje private są widoczne tylko dla kontraktu, w którym zostały zdefiniowane, a nie w kontraktach pochodnych

Zarówno funkcje, jak i zmienne stanu mogą być publiczne lub prywatne

Oto funkcja do aktualizacji zmiennej stanu w kontrakcie:

// Przykład Solidity
function update_name(string value) public {
    dapp_name = value;
}
  • Parametr value typu string jest przekazywany do funkcji: update_name
  • Jest zadeklarowana jako public, co oznacza, że każdy ma do niej dostęp
  • Nie jest zadeklarowana jako view, więc może modyfikować stan kontraktu

Funkcje widoku (View)

Funkcje te gwarantują, że nie zmodyfikują stanu danych kontraktu. Typowymi przykładami są funkcje typu „getter” – możesz ich użyć na przykład do pobrania salda użytkownika.

// Przykład Solidity
function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerPizzaCount[_owner];
}
dappName: public(string)

@view
@public
def readName() -> string:
  return dappName

Co jest uważane za modyfikację stanu:

  1. Zapisywanie do zmiennych stanu.
  2. Emitowanie zdarzeń (opens in a new tab).
  3. Tworzenie innych kontraktów (opens in a new tab).
  4. Używanie selfdestruct.
  5. Wysyłanie etheru poprzez wywołania (calls).
  6. Wywoływanie jakiejkolwiek funkcji, która nie jest oznaczona jako view lub pure.
  7. Używanie wywołań niskopoziomowych.
  8. Używanie wstawek asemblerowych (inline assembly), które zawierają określone kody operacji (opcodes).

Funkcje konstruktora

Funkcje constructor są wykonywane tylko raz, gdy kontrakt jest po raz pierwszy wdrażany. Podobnie jak constructor w wielu klasowych językach programowania, funkcje te często inicjują zmienne stanu do określonych wartości.

# Przykład Vyper

@external
def __init__(_beneficiary: address, _bidding_time: uint256):
    self.beneficiary = _beneficiary
    self.auctionStart = block.timestamp
    self.auctionEnd = self.auctionStart + _bidding_time

Wbudowane funkcje

Oprócz zmiennych i funkcji zdefiniowanych w kontrakcie istnieją pewne specjalne wbudowane funkcje. Najbardziej oczywistym przykładem jest:

  • address.send() – Solidity
  • send(address) – Vyper

Pozwalają one kontraktom na wysyłanie ETH na inne konta.

Pisanie funkcji

Twoja funkcja potrzebuje:

  • zmiennej parametru i typu (jeśli przyjmuje parametry)
  • deklaracji internal/external
  • deklaracji pure/view/payable
  • typu zwracanego (jeśli zwraca wartość)

Kompletny kontrakt może wyglądać mniej więcej tak. Tutaj funkcja constructor zapewnia początkową wartość dla zmiennej dapp_name.

Zdarzenia i logi

Zdarzenia umożliwiają inteligentnemu kontraktowi komunikację z frontendem lub innymi subskrybującymi aplikacjami. Po zatwierdzeniu transakcji i dodaniu jej do bloku, inteligentne kontrakty mogą emitować zdarzenia i logować informacje, które frontend może następnie przetwarzać i wykorzystywać.

Przykłady z adnotacjami

Oto kilka przykładów napisanych w języku Solidity. Jeśli chcesz pobawić się kodem, możesz wejść z nim w interakcję w Remix (opens in a new tab).

Hello world

Token

Unikalne aktywo cyfrowe

Dalsza lektura

Zapoznaj się z dokumentacją Solidity i Vyper, aby uzyskać pełniejszy przegląd inteligentnych kontraktów: