Języki inteligentnych kontraktów
Wspaniałym aspektem Ethereum jest to, że inteligentne kontrakty mogą być programowane przy użyciu języków stosunkowo przyjaznych dla programistów. Jeśli masz doświadczenie z językiem Python lub jakimkolwiek językiem z nawiasami klamrowymi (opens in a new tab), znajdziesz język o znajomej składni.
Dwa najbardziej aktywne i utrzymywane języki to:
- Solidity
- Vyper
Remix IDE zapewnia kompleksowe środowisko programistyczne do tworzenia i testowania kontraktów zarówno w Solidity, jak i Vyper. Wypróbuj przeglądarkowe Remix IDE (opens in a new tab), aby zacząć kodować.
Bardziej doświadczeni programiści mogą również chcieć użyć Yul, języka pośredniego dla Wirtualnej Maszyny Ethereum (EVM), lub Yul+, rozszerzenia dla Yul.
Jeśli jesteś ciekawy i lubisz pomagać w testowaniu nowych języków, które wciąż są w fazie intensywnego rozwoju, możesz poeksperymentować z Fe, nowo powstającym językiem inteligentnych kontraktów, który obecnie wciąż jest w powijakach.
Wymagania wstępne
Wcześniejsza znajomość języków programowania, zwłaszcza JavaScript lub Python, może pomóc w zrozumieniu różnic między językami inteligentnych kontraktów. Zalecamy również zrozumienie inteligentnych kontraktów jako koncepcji przed zbytnim zagłębianiem się w porównania języków. Wprowadzenie do inteligentnych kontraktów.
Solidity
- Zorientowany obiektowo język wysokiego poziomu do implementacji inteligentnych kontraktów.
- Język z nawiasami klamrowymi, na który największy wpływ miał C++.
- Statycznie typowany (typ zmiennej jest znany w czasie kompilacji).
- Obsługuje:
- Dziedziczenie (możesz rozszerzać inne kontrakty).
- Biblioteki (możesz tworzyć kod wielokrotnego użytku, który można wywoływać z różnych kontraktów – podobnie jak funkcje statyczne w klasie statycznej w innych obiektowych językach programowania).
- Złożone typy definiowane przez użytkownika.
Ważne linki
- Dokumentacja (opens in a new tab)
- Portal języka Solidity (opens in a new tab)
- Solidity na przykładach (opens in a new tab)
- GitHub (opens in a new tab)
- Czat Solidity na Gitterze (opens in a new tab) połączony z czatem Solidity na Matrixie (opens in a new tab)
- Ściągawka (opens in a new tab)
- Blog Solidity (opens in a new tab)
- Twitter Solidity (opens in a new tab)
Przykładowy kontrakt
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.7.0;
contract Coin {
// Słowo kluczowe "public" sprawia, że zmienne są
// dostępne z innych kontraktów
address public minter;
mapping (address => uint) public balances;
// Zdarzenia pozwalają klientom reagować na określone
// zmiany w kontrakcie, które zadeklarujesz
event Sent(address from, address to, uint amount);
// Kod konstruktora jest uruchamiany tylko wtedy, gdy kontrakt
// jest tworzony
constructor() {
minter = msg.sender;
}
// Wysyła określoną ilość nowo utworzonych monet na adres
// Może być wywołane tylko przez twórcę kontraktu
function mint(address receiver, uint amount) public {
require(msg.sender == minter);
require(amount < 1e60);
balances[receiver] += amount;
}
// Wysyła określoną ilość istniejących monet
// od dowolnego wywołującego na adres
function send(address receiver, uint amount) public {
require(amount <= balances[msg.sender], "Insufficient balance.");
balances[msg.sender] -= amount;
balances[receiver] += amount;
emit Sent(msg.sender, receiver, amount);
}
}
Ten przykład powinien dać ci wyobrażenie o tym, jak wygląda składnia kontraktu w Solidity. Bardziej szczegółowy opis funkcji i zmiennych znajdziesz w dokumentacji (opens in a new tab).
Vyper
- Język programowania w stylu Pythona
- Silne typowanie
- Mały i zrozumiały kod kompilatora
- Wydajne generowanie kodu bajtowego
- Celowo posiada mniej funkcji niż Solidity, aby kontrakty były bezpieczniejsze i łatwiejsze do audytu. Vyper nie obsługuje:
- Modyfikatorów
- Dziedziczenia
- Wstawek w asemblerze (inline assembly)
- Przeciążania funkcji
- Przeciążania operatorów
- Wywołań rekurencyjnych
- Pętli o nieskończonej długości
- Binarnych punktów stałych
Aby uzyskać więcej informacji, przeczytaj uzasadnienie dla języka Vyper (opens in a new tab).
Ważne linki
- Dokumentacja (opens in a new tab)
- Vyper na przykładach (opens in a new tab)
- Więcej przykładów w Vyper (opens in a new tab)
- GitHub (opens in a new tab)
- Czat społeczności Vyper na Discordzie (opens in a new tab)
- Ściągawka (opens in a new tab)
- Frameworki i narzędzia do tworzenia inteligentnych kontraktów dla Vyper
- VyperPunk - naucz się zabezpieczać i hakować inteligentne kontrakty w Vyper (opens in a new tab)
- Vyper Hub dla programistów (opens in a new tab)
- Najlepsze przykłady inteligentnych kontraktów w Vyper (opens in a new tab)
- Wyselekcjonowane zasoby Awesome Vyper (opens in a new tab)
Przykład
# Otwarta aukcja
# Parametry aukcji
# Beneficjent otrzymuje pieniądze od osoby, która złożyła najwyższą ofertę
beneficiary: public(address)
auctionStart: public(uint256)
auctionEnd: public(uint256)
# Obecny stan aukcji
highestBidder: public(address)
highestBid: public(uint256)
# Ustawiane na true na końcu, uniemożliwia jakiekolwiek zmiany
ended: public(bool)
# Śledzenie zwróconych ofert, aby móc zastosować wzorzec wypłaty
pendingReturns: public(HashMap[address, uint256])
# Utwórz prostą aukcję z czasem licytacji `_bidding_time`
# sekund w imieniu
# adresu beneficjenta `_beneficiary`.
@external
def __init__(_beneficiary: address, _bidding_time: uint256):
self.beneficiary = _beneficiary
self.auctionStart = block.timestamp
self.auctionEnd = self.auctionStart + _bidding_time
# Licytuj w aukcji za pomocą wartości wysłanej
# razem z tą transakcją.
# Wartość zostanie zwrócona tylko wtedy, gdy
# aukcja nie zostanie wygrana.
@external
@payable
def bid():
# Sprawdź, czy okres licytacji się zakończył.
assert block.timestamp < self.auctionEnd
# Sprawdź, czy oferta jest wystarczająco wysoka
assert msg.value > self.highestBid
# Śledź zwrot dla poprzedniego licytanta z najwyższą ofertą
self.pendingReturns[self.highestBidder] += self.highestBid
# Śledź nową najwyższą ofertę
self.highestBidder = msg.sender
self.highestBid = msg.value
# Wypłać wcześniej zwróconą ofertę. Wzorzec wypłaty jest
# użyty tutaj, aby uniknąć problemu z bezpieczeństwem. Gdyby zwroty były bezpośrednio
# wysyłane jako część bid(), złośliwy kontrakt licytujący mógłby zablokować
# te zwroty i tym samym zablokować napływ nowych, wyższych ofert.
@external
def withdraw():
pending_amount: uint256 = self.pendingReturns[msg.sender]
self.pendingReturns[msg.sender] = 0
send(msg.sender, pending_amount)
# Zakończ aukcję i wyślij najwyższą ofertę
# do beneficjenta.
@external
def endAuction():
# Dobrą praktyką jest strukturyzowanie funkcji, które wchodzą w interakcje
# z innymi kontraktami (tj. wywołują funkcje lub wysyłają ether)
# w trzy fazy:
# 1. sprawdzanie warunków
# 2. wykonywanie akcji (potencjalnie zmieniających warunki)
# 3. interakcja z innymi kontraktami
# Jeśli te fazy zostaną pomieszane, inny kontrakt mógłby wywołać
# z powrotem obecny kontrakt i zmodyfikować stan lub spowodować,
# że efekty (wypłata etheru) zostaną wykonane wielokrotnie.
# Jeśli funkcje wywoływane wewnętrznie obejmują interakcję z zewnętrznymi
# kontraktami, muszą być one również traktowane jako interakcja z
# zewnętrznymi kontraktami.
# 1. Warunki
# Sprawdź, czy czas zakończenia aukcji został osiągnięty
assert block.timestamp >= self.auctionEnd
# Sprawdź, czy ta funkcja została już wywołana
assert not self.ended
# 2. Efekty
self.ended = True
# 3. Interakcja
send(self.beneficiary, self.highestBid)
Ten przykład powinien dać ci wyobrażenie o tym, jak wygląda składnia kontraktu w Vyper. Bardziej szczegółowy opis funkcji i zmiennych znajdziesz w dokumentacji (opens in a new tab).
Yul i Yul+
Jeśli jesteś nowy w Ethereum i nie programowałeś jeszcze w językach inteligentnych kontraktów, zalecamy rozpoczęcie od Solidity lub Vyper. Zainteresuj się Yul lub Yul+ dopiero wtedy, gdy zapoznasz się z najlepszymi praktykami bezpieczeństwa inteligentnych kontraktów i specyfiką pracy z Wirtualną Maszyną Ethereum (EVM).
Yul
- Język pośredni dla Ethereum.
- Obsługuje EVM oraz Ewasm (opens in a new tab), czyli WebAssembly w wersji dla Ethereum, i został zaprojektowany jako użyteczny wspólny mianownik obu platform.
- Dobry cel dla etapów optymalizacji wysokiego poziomu, z których mogą w równym stopniu korzystać platformy EVM i Ewasm.
Yul+
- Niskopoziomowe, wysoce wydajne rozszerzenie dla Yul.
- Początkowo zaprojektowane dla kontraktu typu optymistyczny rollup.
- Yul+ można traktować jako eksperymentalną propozycję aktualizacji dla Yul, dodającą do niego nowe funkcje.
Ważne linki
- Dokumentacja Yul (opens in a new tab)
- Dokumentacja Yul+ (opens in a new tab)
- Wpis wprowadzający do Yul+ (opens in a new tab)
Przykładowy kontrakt
Poniższy prosty przykład implementuje funkcję potęgowania. Można go skompilować za pomocą solc --strict-assembly --bin input.yul. Przykład powinien zostać zapisany w pliku input.yul.
{
function power(base, exponent) -> result
{
switch exponent
case 0 { result := 1 }
case 1 { result := base }
default
{
result := power(mul(base, base), div(exponent, 2))
if mod(exponent, 2) { result := mul(base, result) }
}
}
let res := power(calldataload(0), calldataload(32))
mstore(0, res)
return(0, 32)
}
Jeśli masz już duże doświadczenie z inteligentnymi kontraktami, pełną implementację ERC-20 w Yul znajdziesz tutaj (opens in a new tab).
Fe
- Statycznie typowany język dla Wirtualnej Maszyny Ethereum (EVM).
- Zainspirowany przez Python i Rust.
- Ma być łatwy do nauki – nawet dla programistów, którzy są nowi w ekosystemie Ethereum.
- Rozwój Fe jest wciąż na wczesnym etapie, język miał swoje wydanie alfa w styczniu 2021 roku.
Ważne linki
- GitHub (opens in a new tab)
- Ogłoszenie Fe (opens in a new tab)
- Mapa drogowa Fe na 2021 rok (opens in a new tab)
- Czat Fe na Discordzie (opens in a new tab)
- Twitter Fe (opens in a new tab)
Przykładowy kontrakt
Poniżej znajduje się prosty kontrakt zaimplementowany w Fe.
type BookMsg = bytes[100]
contract GuestBook:
pub guest_book: map<address, BookMsg>
event Signed:
book_msg: BookMsg
pub def sign(book_msg: BookMsg):
self.guest_book[msg.sender] = book_msg
emit Signed(book_msg=book_msg)
pub def get_msg(addr: address) -> BookMsg:
return self.guest_book[addr].to_mem()
Jak wybrać
Podobnie jak w przypadku każdego innego języka programowania, chodzi głównie o wybór odpowiedniego narzędzia do odpowiedniego zadania, a także o osobiste preferencje.
Oto kilka rzeczy do rozważenia, jeśli nie próbowałeś jeszcze żadnego z tych języków:
Co jest wspaniałego w Solidity?
- Jeśli jesteś początkujący, dostępnych jest wiele samouczków i narzędzi do nauki. Więcej na ten temat znajdziesz w sekcji Nauka przez kodowanie.
- Dostępne są dobre narzędzia dla programistów.
- Solidity ma dużą społeczność programistów, co oznacza, że najprawdopodobniej dość szybko znajdziesz odpowiedzi na swoje pytania.
Co jest wspaniałego w Vyper?
- Świetny sposób na rozpoczęcie pracy dla programistów Pythona, którzy chcą pisać inteligentne kontrakty.
- Vyper ma mniejszą liczbę funkcji, co czyni go świetnym do szybkiego prototypowania pomysłów.
- Vyper ma być łatwy do audytu i maksymalnie czytelny dla człowieka.
Co jest wspaniałego w Yul i Yul+?
- Uproszczony i funkcjonalny język niskopoziomowy.
- Pozwala znacznie zbliżyć się do surowego EVM, co może pomóc zoptymalizować zużycie gazu przez twoje kontrakty.
Porównania języków
Aby porównać podstawową składnię, cykl życia kontraktu, interfejsy, operatory, struktury danych, funkcje, przepływ sterowania i inne, sprawdź tę ściągawkę od Auditless (opens in a new tab)