Języki inteligentnych kontraktów
Ostatnia edycja: @Beas(opens in a new tab), 17 czerwca 2024
Świetnym aspektem Ethereum jest to, że inteligentne kontrakty można programować przy użyciu stosunkowo przyjaznych dla programistów języków. Jeśli masz doświadczenie z Pythonem lub JavaScript, możesz znaleźć język o znanej składni.
Dwa najbardziej aktywne i obsługiwane języki to:
- Solidity
- Vyper
Bardziej doświadczeni programiści mogą również użyć Yul, pośredniego języka dla wirtualnej maszyny Ethereum, lub Yul+, rozszerzenia Yul.
Warunki wstępne
Wcześniejsza znajomość języków programowania, zwłaszcza JavaScript lub Python, może pomóc w zrozumieniu różnic w językach inteligentnych kontraktów. Zalecamy również zrozumienie inteligentnych kontraktów jako koncepcji przed zbytnim zagłębieniem się w porównania języków. Wprowadzenie do inteligentnych kontraktów.
Solidity
- Wpłynęły na niego języki C++, Python i JavaScript.
- Typowanie statyczne (typ zmiennej jest znany w czasie kompilacji).
- Obsługuje:
- Dziedziczenie (możesz rozszerzać inne kontrakty).
- Biblioteki (można utworzyć kod wielokrotnego użytku, który można wywoływać z różnych kontraktów — jak funkcje statyczne w klasie statycznej w innych językach programowania obiektowego).
- Złożone typy zdefiniowane przez użytkownika.
Ważne linki
- Dokumentacja(opens in a new tab)
- Portal poświęcony językowi Solidity(opens in a new tab)
- Solidity w przykładach(opens in a new tab)
- GitHub(opens in a new tab)
- Czat dotyczący Solidity na Glitterze(opens in a new tab)
- Ściągawka(opens in a new tab)
- Blog poświęcony Solidity(opens in a new tab)
Przykładowy kontrakt
1// SPDX-License-Identifier: GPL-3.02pragma solidity >= 0.7.0;34contract Coin {5 // The keyword "public" makes variables6 // accessible from other contracts7 address public minter;8 mapping (address => uint) public balances;910 // Events allow clients to react to specific11 // contract changes you declare12 event Sent(address from, address to, uint amount);1314 // Constructor code is only run when the contract15 // is created16 constructor() {17 minter = msg.sender;18 }1920 // Sends an amount of newly created coins to an address21 // Can only be called by the contract creator22 function mint(address receiver, uint amount) public {23 require(msg.sender == minter);24 require(amount < 1e60);25 balances[receiver] += amount;26 }2728 // Sends an amount of existing coins29 // from any caller to an address30 function send(address receiver, uint amount) public {31 require(amount <= balances[msg.sender], "Insufficient balance.");32 balances[msg.sender] -= amount;33 balances[receiver] += amount;34 emit Sent(msg.sender, receiver, amount);35 }36}Pokaż wszystkoKopiuj
Ten przykład powinien dać wyobrażenie o składni kontraktu Solidity. Bardziej szczegółowy opis funkcji i zmiennych znajdziesz w dokumentacji(opens in a new tab).
Vyper
- Pythonowy język programowania
- Silne typowanie
- Niewielki i zrozumiały kod kompilatora
- Celowo ma mniej funkcji niż Solidity, aby zwiększyć bezpieczeństwo kontraktów i ułatwić ich audyt. Nieobsługiwane przez Vyper:
- Modyfikatory
- Dziedziczenie
- Wbudowany asembler
- Przeciążenie funkcji
- Przeciążenie operatora
- Wywołania rekurencyjne
- Pętle o nieskończonej długości
- Binarnej arytmetyki stałoprzecinkowej
Aby uzyskać więcej informacji, przeczytaj artykuł o podstawach Vypera(opens in a new tab).
Ważne linki
- Dokumentacja(opens in a new tab)
- Vyper w przykładach(opens in a new tab)
- GitHub(opens in a new tab)
- Czat poświęcony Vyperowi na Gitterze(opens in a new tab)
- Ściągawka(opens in a new tab)
- Aktualizacja 8 stycznia 2020 r(opens in a new tab)
Przykład
1# Open Auction23# Auction params4# Beneficiary receives money from the highest bidder5beneficiary: public(address)6auctionStart: public(uint256)7auctionEnd: public(uint256)89# Current state of auction10highestBidder: public(address)11highestBid: public(uint256)1213# Set to true at the end, disallows any change14ended: public(bool)1516# Keep track of refunded bids so we can follow the withdraw pattern17pendingReturns: public(HashMap[address, uint256])1819# Create a simple auction with `_bidding_time`20# seconds bidding time on behalf of the21# beneficiary address `_beneficiary`.22@external23def __init__(_beneficiary: address, _bidding_time: uint256):24 self.beneficiary = _beneficiary25 self.auctionStart = block.timestamp26 self.auctionEnd = self.auctionStart + _bidding_time2728# Bid on the auction with the value sent29# together with this transaction.30# The value will only be refunded if the31# auction is not won.3233@external34@payable35def bid():36 # Check if bidding period is over.37 assert block.timestamp < self.auctionEnd38 # Check if bid is high enough39 assert msg.value > self.highestBid40 # Track the refund for the previous high bidder41 self.pendingReturns[self.highestBidder] += self.highestBid42 # Track new high bid43 self.highestBidder = msg.sender44 self.highestBid = msg.value4546# Withdraw a previously refunded bid. The withdraw pattern is47# used here to avoid a security issue. If refunds were directly48# sent as part of bid(), a malicious bidding contract could block49# those refunds and thus block new higher bids from coming in.50@external51def withdraw():52 pending_amount: uint256 = self.pendingReturns[msg.sender]53 self.pendingReturns[msg.sender] = 054 send(msg.sender, pending_amount)5556# End the auction and send the highest bid57# to the beneficiary.58@external59def endAuction():60 # It is a good guideline to structure functions that interact61 # with other contracts (i.e. they call functions or send Ether)62 # into three phases:63 # 1. checking conditions64 # 2. performing actions (potentially changing conditions)65 # 3. interacting with other contracts66 # If these phases are mixed up, the other contract could call67 # back into the current contract and modify the state or cause68 # effects (ether payout) to be performed multiple times.69 # If functions called internally include interaction with external70 # contracts, they also have to be considered interaction with71 # external contracts.7273 # 1. Conditions74 # Check if auction endtime has been reached75 assert block.timestamp >= self.auctionEnd76 # Check if this function has already been called77 assert not self.ended7879 # 2.80 Effects81 self.ended = True8283 # 3. Interaction84 send(self.beneficiary, self.highestBid)Pokaż wszystkoKopiuj
Ten przykład powinien dać wyobrażenie o składni kontraktu Vyper. Aby uzyskać bardziej szczegółowy opis funkcji i zmiennych, zobacz dokumentację(opens in a new tab).
Yul i Yul+
Jeśli dopiero zapoznajesz się z Ethereum i nie kodowałeś jeszcze w językach kontraktów inteligentnych, zalecamy rozpoczęcie pracy od Solidity lub Vyper. Zajrzyj do Yul lub Yul+ dopiero po zapoznaniu się z najlepszymi praktykami w zakresie bezpieczeństwa inteligentnych kontraktów i specyfiką pracy z EVM.
Yul
- Język pośredni dla Ethereum.
- Obsługuje EVM i eWASM(opens in a new tab), Ethereum flavored WebAssembly, zaprojektowany tak, aby był użytecznym wspólnym mianownikiem obu platform.
- Dobry cel dla etapów optymalizacji wysokiego poziomu, które mogą przynieść korzyści zarówno platformom EVM, jak i eWASM.
Yul+
- Niskopoziomowe, bardzo wydajne rozszerzenie do Yul.
- Początkowo zaprojektowany na potrzeby kontraktu typu optymistyczna wartość zbiorcza.
- Yul+ można postrzegać jako eksperymentalną propozycję ulepszenia Yul, dodającą do niego nowe funkcje.
Ważne linki
- Dokumentacja Yul(opens in a new tab)
- Dokumentacja Yul+(opens in a new tab)
- Yul+ Playground(opens in a new tab)
- Post wprowadzający do Yul+(opens in a new tab)
Przykładowy kontrakt
Poniższy prosty przykład implementuje funkcję potęgową. Można go skompilować, używając solc --strict-assembly --bin input.yul
. Przykład należy zapisać w pliku input.yul.
1{2 function power(base, exponent) -> result3 {4 switch exponent5 case 0 { result := 1 }6 case 1 { result := base }7 default8 {9 result := power(mul(base, base), div(exponent, 2))10 if mod(exponent, 2) { result := mul(base, result) }11 }12 }13 let res := power(calldataload(0), calldataload(32))14 mstore(0, res)15 return(0, 32)16}Pokaż wszystko
Jeśli masz już duże doświadczenie w inteligentnych kontraktach, pełną implementację ERC20 w Yul znajdziesz tutaj(opens in a new tab).
Jak wybrać
Podobnie jak w przypadku każdego innego języka programowania, najczęściej chodzi o wybór odpowiedniego narzędzia do danej pracy, jak również o osobiste preferencje.
Oto kilka rzeczy do rozważenia, jeśli nie próbowałeś jeszcze żadnego z języków:
Co jest wspaniałego w Solidity?
- Jeśli dopiero zaczynasz, jest tam wiele samouczków i narzędzi do nauki. Więcej informacji zawiera artykuł Ucz się przez kodowanie.
- Dostępne dobre narzędzia programistyczne.
- Solidity ma dużą społeczność programistów, co oznacza, że najprawdopodobniej 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, dzięki czemu świetnie nadaje się do szybkiego prototypowania pomysłów.
- Vyper ma być łatwy do skontrolowania i w największym stopniu czytelny dla człowieka.
Co jest wspaniałego w Yul i Yul+?
- Uproszczony i funkcjonalny język niskiego poziomu.
- Pozwala zbliżyć się do pierwotnej EVM, co może pomóc zoptymalizować zużycie gazu w Twoich kontraktach.
Porównania języków
Aby porównać podstawową składnię, cykl życia kontraktu, interfejsy, operatory, struktury danych, funkcje, przepływ kontroli itd., sprawdź tę ściągawkę firmy Auditless(opens in a new tab)