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

Języki inteligentnych kontraktów

Ostatnia edycja: @Beas(opens in a new tab), 23 lutego 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.

Przykładowy kontrakt

1// SPDX-License-Identifier: GPL-3.0
2pragma solidity >= 0.7.0;
3
4contract Coin {
5 // The keyword "public" makes variables
6 // accessible from other contracts
7 address public minter;
8 mapping (address => uint) public balances;
9
10 // Events allow clients to react to specific
11 // contract changes you declare
12 event Sent(address from, address to, uint amount);
13
14 // Constructor code is only run when the contract
15 // is created
16 constructor() {
17 minter = msg.sender;
18 }
19
20 // Sends an amount of newly created coins to an address
21 // Can only be called by the contract creator
22 function mint(address receiver, uint amount) public {
23 require(msg.sender == minter);
24 require(amount < 1e60);
25 balances[receiver] += amount;
26 }
27
28 // Sends an amount of existing coins
29 // from any caller to an address
30 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ż wszystko
Kopiuj

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).

Przykład

1# Open Auction
2
3# Auction params
4# Beneficiary receives money from the highest bidder
5beneficiary: public(address)
6auctionStart: public(uint256)
7auctionEnd: public(uint256)
8
9# Current state of auction
10highestBidder: public(address)
11highestBid: public(uint256)
12
13# Set to true at the end, disallows any change
14ended: public(bool)
15
16# Keep track of refunded bids so we can follow the withdraw pattern
17pendingReturns: public(HashMap[address, uint256])
18
19# Create a simple auction with `_bidding_time`
20# seconds bidding time on behalf of the
21# beneficiary address `_beneficiary`.
22@external
23def __init__(_beneficiary: address, _bidding_time: uint256):
24 self.beneficiary = _beneficiary
25 self.auctionStart = block.timestamp
26 self.auctionEnd = self.auctionStart + _bidding_time
27
28# Bid on the auction with the value sent
29# together with this transaction.
30# The value will only be refunded if the
31# auction is not won.
32
33@external
34@payable
35def bid():
36 # Check if bidding period is over.
37 assert block.timestamp < self.auctionEnd
38 # Check if bid is high enough
39 assert msg.value > self.highestBid
40 # Track the refund for the previous high bidder
41 self.pendingReturns[self.highestBidder] += self.highestBid
42 # Track new high bid
43 self.highestBidder = msg.sender
44 self.highestBid = msg.value
45
46# Withdraw a previously refunded bid. The withdraw pattern is
47# used here to avoid a security issue. If refunds were directly
48# sent as part of bid(), a malicious bidding contract could block
49# those refunds and thus block new higher bids from coming in.
50@external
51def withdraw():
52 pending_amount: uint256 = self.pendingReturns[msg.sender]
53 self.pendingReturns[msg.sender] = 0
54 send(msg.sender, pending_amount)
55
56# End the auction and send the highest bid
57# to the beneficiary.
58@external
59def endAuction():
60 # It is a good guideline to structure functions that interact
61 # with other contracts (i.e. they call functions or send Ether)
62 # into three phases:
63 # 1. checking conditions
64 # 2. performing actions (potentially changing conditions)
65 # 3. interacting with other contracts
66 # If these phases are mixed up, the other contract could call
67 # back into the current contract and modify the state or cause
68 # effects (ether payout) to be performed multiple times.
69 # If functions called internally include interaction with external
70 # contracts, they also have to be considered interaction with
71 # external contracts.
72
73 # 1. Conditions
74 # Check if auction endtime has been reached
75 assert block.timestamp >= self.auctionEnd
76 # Check if this function has already been called
77 assert not self.ended
78
79 # 2.
80 Effects
81 self.ended = True
82
83 # 3. Interaction
84 send(self.beneficiary, self.highestBid)
Pokaż wszystko
Kopiuj

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.

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) -> result
3 {
4 switch exponent
5 case 0 { result := 1 }
6 case 1 { result := base }
7 default
8 {
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)

Dalsza lektura

Czy ten artykuł był pomocny?