Salt la conținutul principal
Change page

Anatomia contractelor inteligente

Ultima modificare: @nicklcanada(opens in a new tab), 19 noiembrie 2023

Un contract inteligent este un program care rulează la o adresă pe Ethereum. Este alcătuit din date și funcții care pot fi executate la primirea unei tranzacții. Iată o imagine de ansamblu a ceea ce constituie un contract inteligent.

Condiții prealabile

Aveţi grijă să citiţi mai întâi despre contractele inteligente. Acest document presupune că sunteţi deja familiarizat cu limbaje de programarea precum JavaScript sau Python.

Datele

Toate datele dintr-un contract trebuie alocate unei locații: fie de stocare, fie de memorie. Este costisitor de modificat locul de stocare într-un contract inteligent, deci trebuie să hotărâţi unde să vă plasaţi datele.

Stocare

Datele persistente sunt denumite stocare și sunt reprezentate de variabilele de stare. Aceste valori sunt stocate permanent pe blockchain. Trebuie să declaraţi de ce tip sunt, astfel încât contractul să poată ţine socoteala spaţiului de stocare de care are nevoie pe blockchain atunci când compilează.

1// Exemplu Solidity
2contract SimpleStorage {
3 uint storedData; // Stare variabilă
4 // ...
5}
Copiați
1# Exemplu Vyper
2storedData: int128
Copiați

Dacă aţi programat deja în limbaje orientate pe obiecte, probabil că știţi deja majoritatea tipurilor. Cu toate acestea, address (adresa) ar trebui să fie nouă pentru dvs. dacă nu aţi mai dezvoltat pe Ethereum.

Un tip de address poate conține o adresă Ethereum care echivalează cu 20 de octeţi sau 160 de biți. Acesta răspunde în notație hexazecimală cu un 0x la început.

Alte tipuri includ:

  • boolean
  • întreg
  • numere în virgulă fixă
  • matrice de octeți de dimensiuni fixe
  • matrice de octeți de dimensiuni dinamice
  • literale raționale și întregi
  • literale de tip string
  • literale hexazecimale
  • enum-uri

Pentru mai multe explicații, consultaţi documentele:

Memorie

Valorile care sunt stocate numai pe durata de viață a executării unei funcții contractuale se numesc variabile de memorie. Deoarece acestea nu sunt stocate permanent pe blockchain, sunt mult mai ieftin de utilizat.

Aflaţi mai multe informații despre modul în care EVM stochează datele (stocare, memorie și stivă) în documentația Solidity(opens in a new tab).

Variabile de mediu

În plus față de variabilele pe care le definiţi în contract, există câteva variabile globale speciale. Acestea sunt utilizate în principal pentru a furniza informații despre blockchain sau tranzacția curentă.

Exemple:

PropVariabilă de stareDescriere
block.timestampuint256Marca temporală actuală a epocii blocului
msg.senderaddressExpeditorul mesajului (apel curent)

Funcții

În exprimare simplistă, funcțiile pot obține informații sau pot seta informații ca răspuns la tranzacțiile primite.

Există două tipuri de apeluri funcționale:

  • internal – acestea nu creează un apel EVM
    • Funcțiile interne și variabilele de stare pot fi accesate numai intern (adică din contractul actual sau contractele care derivă din acesta)
  • external – acestea creează un apel EVM
    • Funcțiile externe fac parte din interfața contractului, ceea ce înseamnă că pot fi apelate din alte contracte și prin tranzacții. O funcție externă f nu poate fi apelată intern (adică f() nu funcționează, dar this.f() funcționează).

De asemenea, pot fi de tip public sau private

  • funcțiile de tip public pot fi apelate intern din cadrul contractului sau extern prin mesaje
  • funcțiile private sunt vizibile numai pentru contractul în care sunt definite și nu sunt vizibile în contractele derivate

Atât funcțiile, cât și variabilele de stare pot fi făcute publice sau private

Iată o funcție pentru actualizarea unei variabile de stare pe un contract:

1// Exemplu Solidity
2function update_name(string value) public {
3 dapp_name = value;
4}
Copiați
  • Parametrul value de tip string este trecut în funcția: update_name
  • Este declarat public, ceea ce înseamnă că oricine îl poate accesa
  • Nu este declarat view, astfel încât să poată modifica starea contractului

Funcții de vizualizare

Aceste funcții promit să nu modifice starea datelor contractului. Exemplele obişnuite sunt funcțiile „getter” (de obținere) – s-ar putea să utilizaţi acest lucru pentru a primi soldul unui utilizator, de exemplu.

1// Exemplu Solidity
2function balanceOf(address _owner) public view returns (uint256 _balance) {
3 return ownerPizzaCount[_owner];
4}
Copiați
1dappName: public(string)
2
3@view
4@public
5def readName() -> string:
6 return dappName
Copiați

Ce se consideră ca modificator de stare:

  1. Scrierea în variabilele de stare.
  2. Emiterea de evenimente(opens in a new tab).
  3. Crearea altor contracte(opens in a new tab).
  4. Folosirea selfdestruct.
  5. Trimiterea de ether prin apeluri.
  6. Apelarea oricărei funcții care nu este marcată view sau pure.
  7. Folosirea de apeluri de nivel inferior.
  8. Utilizarea ansamblului în linie care conține anumite opcoduri.

Funcții constructor

Funcțiile constructor sunt executate o singură dată, la prima implementare a contractului. Precum constructor-ul din multe limbaje de programare bazate pe clase, aceste funcții inițializează adesea variabilele de stare la valorile lor specificate.

1// Exemplu Solidity
2// Inițializează datele contractului, setând `proprietarul`
3// la adresa creatorului contractului.
4constructor() public {
5 // Toate contractele inteligente se bazează pe tranzacții externe pentru a le declanșa funcțiile.
6 // `msg`este o variabilă globală care include date relevante privind tranzacția dată,
7 // cum ar fi adresa expeditorului și valoarea ETH inclusă în tranzacție.
8 // Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
9 owner = msg.sender;
10}
Afișează tot
Copiați
1# exemplu Vyper
2
3@external
4def __init__(_beneficiary: address, _bidding_time: uint256):
5 self.beneficiary = _beneficiary
6 self.auctionStart = block.timestamp
7 self.auctionEnd = self.auctionStart + _bidding_time
Copiați

Funcții încorporate

În plus față de variabilele și funcțiile pe care le definiţi în contract, există câteva funcții speciale încorporate. Cel mai evident exemplu este:

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

Acestea permit contractelor să trimită ETH către alte conturi.

Scrierea de funcții

Funcția dvs. are nevoie de:

  • parametru variabil și tipul acestuia (dacă acceptă parametri)
  • declararea dacă este internal/external
  • declararea dacă este pure/view/payable
  • tipul de răspuns (dacă răspunde printr-o valoare)
1pragma solidity >=0.4.0 <=0.6.0;
2
3contract ExampleDapp {
4 string dapp_name; // state variable
5
6 // Called when the contract is deployed and initializes the value
7 constructor() public {
8 dapp_name = "My Example dapp";
9 }
10
11 // Get Function
12 function read_name() public view returns(string) {
13 return dapp_name;
14 }
15
16 // Set Function
17 function update_name(string value) public {
18 dapp_name = value;
19 }
20}
Afișează tot
Copiați

Un contract complet ar putea arăta astfel. Aici funcția constructor furnizează o valoare inițială pentru variabila dapp_name.

Evenimente și jurnale

Evenimentele vă permit să comunicaţi cu contractul dvs. inteligent din frontend sau din alte aplicații cu abonare. Când o tranzacție este minată, contractele inteligente pot emite evenimente și pot scrie jurnale în blockchain, pe care frontend-ul le poate procesa.

Exemple adnotate

Acestea sunt câteva exemple scrise în Solidity. Dacă doriţi să vă jucaţi cu codul, puteţi interacționa cu el în Remix(opens in a new tab).

Hello world

1// Specifică versiunea Solidity, utilizând versiuni semantice.
2// Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
3pragma solidity ^0.5.10;
4
5// Definește un contract numit `HelloWorld`.
6// Un contract este o colecție de funcții și date - (starea sa).
7// Odată implementat, un contract se află la o anumită adresă din blockchain-ul Ethereum.
8// Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
9contract HelloWorld {
10
11 // Declară o variabilă de stare `message` de tip `string`.
12 // Variabilele de stare sunt variabile ale căror valori sunt stocate permanent în stocarea contractului.
13 // Cuvântul cheie `public` face variabile accesibile din afara unui contract
14 // și creează o funcție pe care alte contracte sau clienți o pot apela pentru a accesa valoarea.
15 string public message;
16
17 // Similar cu multe limbaje orientate pe obiecte bazate pe clase, un constructor este
18 // o funcție specială care se execută numai la crearea contractului.
19 // Funcțiile constructor sunt utilizate pentru a inițializa datele contractului.
20 // Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
21 constructor(string memory initMessage) public {
22 // Acceptă un argument de string `initMessage` și setează valoarea
23 // în variabila de stocare `message` a contractului).
24 message = initMessage;
25 }
26
27 // O funcție publică care acceptă un argument string
28 // și actualizează variabila de stocare `message`.
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
Afișează tot
Copiați

Token

1pragma solidity ^0.5.10;
2
3contract Token {
4 // `address` este comparabilă cu o adresă de e-mail - este utilizată pentru a identifica un cont pe Ethereum.
5 // Adresele pot reprezenta un contract inteligent sau un cont extern (utilizator).
6 // Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
7 address public owner;
8
9 // `mapping` este în esență o structură de date de tabel hash.
10 // Acest `mapping` atribuie un număr întreg nesemnat (echilibrul tokenului) unei adrese (deținătorul tokenului).
11 // Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
12 mapping (address => uint) public balances;
13
14 // Evenimentele permit înregistrarea activității pe blockchain.
15 // Clienții Ethereum pot asculta evenimente pentru a reacționa la modificările stării contractului.
16 // Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
17 event Transfer(address from, address to, uint amount);
18
19 // Inițializează datele contractului, setând `owner`
20 // la adresa creatorului contractului.
21 constructor() public {
22 // Toate contractele inteligente se bazează pe tranzacții externe pentru a declanșa funcțiile sale.
23 // `msg` este o variabilă globală care include date relevante despre tranzacția dată,
24 // cum ar fi adresa expeditorului și valoarea ETH inclusă în tranzacție.
25 // Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
26 owner = msg.sender;
27 }
28
29 // Creează o cantitate de tokenuri noi și le trimite la o adresă.
30 function mint(address receiver, uint amount) public {
31 // `require` este o structură de control utilizată pentru a impune anumite condiții.
32 // Dacă o declarație `require` este evaluată ca `false`, se declanșează o excepție,
33 // care întoarce toate modificările aduse stării în timpul apelului curent.
34 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
35
36 // Only the contract owner can call this function
37 require(msg.sender == owner, "You are not the owner.");
38
39 // Enforces a maximum amount of tokens
40 require(amount < 1e60, "Maximum issuance exceeded");
41
42 // Increases the balance of `receiver` by `amount`
43 balances[receiver] += amount;
44 }
45
46 // Sends an amount of existing tokens from any caller to an address.
47 function transfer(address receiver, uint amount) public {
48 // Expeditorul trebuie să aibă suficiente tokenuri pentru a le trimite
49 require(amount <= balances[msg.sender], "Insufficient balance.");
50
51 // Reglează soldurile token ale celor două adrese
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // Emite evenimentul definit anterior
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
Afișează tot
Copiați

Activ digital unic

1pragma solidity ^0.5.10;
2
3// Importă simboluri din alte fișiere în contractul curent.
4// În acest caz, o serie de contracte de ajutor de la OpenZeppelin.
5//Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#importing-other-source-files
6
7import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721.sol";
8import "../node_modules/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
9import "../node_modules/@openzeppelin/contracts/introspection/ERC165.sol";
10import "../node_modules/@openzeppelin/contracts/math/SafeMath.sol";
11
12// Cuvântul cheie `is` este folosit pentru a moșteni funcții și cuvinte cheie din contracte externe.
13// În acest caz, `CryptoPizza` moștenește din contractele `IERC721` și `ERC165`.
14// Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance
15contract CryptoPizza is IERC721, ERC165 {
16 // Folosește biblioteca OpenZeppelin's SafeMath ca să efectuezi operațiuni aritmetice în siguranță.
17 // Află mai multe: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath
18 using SafeMath for uint256;
19
20 // Variabilele de stare constantă din Solidity sunt similare cu alte limbaje
21 // dar trebuie să atribui dintr-o expresie care este constantă în timpul compilării.
22 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constant-state-variables
23 uint256 constant dnaDigits = 10;
24 uint256 constant dnaModulus = 10 ** dnaDigits;
25 bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
26
27 // Struct types let you define your own type
28 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#structs
29 struct Pizza {
30 string name;
31 uint256 dna;
32 }
33
34 // Creates an empty array of Pizza structs
35 Pizza[] public pizzas;
36
37 // Mapping from pizza ID to its owner's address
38 mapping(uint256 => address) public pizzaToOwner;
39
40 // Mapping from owner's address to number of owned token
41 mapping(address => uint256) public ownerPizzaCount;
42
43 // Mapping from token ID to approved address
44 mapping(uint256 => address) pizzaApprovals;
45
46 // You can nest mappings, this example maps owner to operator approvals
47 mapping(address => mapping(address => bool)) private operatorApprovals;
48
49 // Internal function to create a random Pizza from string (name) and DNA
50 function _createPizza(string memory _name, uint256 _dna)
51 // The `internal` keyword means this function is only visible
52 // within this contract and contracts that derive this contract
53 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#visibility-and-getters
54 internal
55 // `isUnique` is a function modifier that checks if the pizza already exists
56 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html#function-modifiers
57 isUnique(_name, _dna)
58 {
59 // Adds Pizza to array of Pizzas and get id
60 uint256 id = SafeMath.sub(pizzas.push(Pizza(_name, _dna)), 1);
61
62 // Checks that Pizza owner is the same as current user
63 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/control-structures.html#error-handling-assert-require-revert-and-exceptions
64
65 // note that address(0) is the zero address,
66 // indicating that pizza[id] is not yet allocated to a particular user.
67
68 assert(pizzaToOwner[id] == address(0));
69
70 // Maps the Pizza to the owner
71 pizzaToOwner[id] = msg.sender;
72 ownerPizzaCount[msg.sender] = SafeMath.add(
73 ownerPizzaCount[msg.sender],
74 1
75 );
76 }
77
78 // Creates a random Pizza from string (name)
79 function createRandomPizza(string memory _name) public {
80 uint256 randDna = generateRandomDna(_name, msg.sender);
81 _createPizza(_name, randDna);
82 }
83
84 // Generates random DNA from string (name) and address of the owner (creator)
85 function generateRandomDna(string memory _str, address _owner)
86 public
87 // Functions marked as `pure` promise not to read from or modify the state
88 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#pure-functions
89 pure
90 returns (uint256)
91 {
92 // Generates random uint from string (name) + address (owner)
93 uint256 rand = uint256(keccak256(abi.encodePacked(_str))) +
94 uint256(_owner);
95 rand = rand % dnaModulus;
96 return rand;
97 }
98
99 // Returns array of Pizzas found by owner
100 function getPizzasByOwner(address _owner)
101 public
102 // Functions marked as `view` promise not to modify state
103 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#view-functions
104 view
105 returns (uint256[] memory)
106 {
107 // Uses the `memory` storage location to store values only for the
108 // lifecycle of this function call.
109 // Află mai multe: https://solidity.readthedocs.io/en/v0.5.10/introduction-to-smart-contracts.html#storage-memory-and-the-stack
110 uint256[] memory result = new uint256[](ownerPizzaCount[_owner]);
111 uint256 counter = 0;
112 for (uint256 i = 0; i < pizzas.length; i++) {
113 if (pizzaToOwner[i] == _owner) {
114 result[counter] = i;
115 counter++;
116 }
117 }
118 return result;
119 }
120
121 // Transferă Pizza și proprietatea asupra altei adrese
122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
123 require(_from != address(0) && _to != address(0), "Adresă invalidă.");
124 require(_exists(_pizzaId), "Pizza nu există.");
125 require(_from != _to, "Nu se poate transfera la aceeași adresă.");
126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Adresa nu este aprobată.");
127
128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
130 pizzaToOwner[_pizzaId] = _to;
131
132 //Emite eveniment definit în contractul IERC721 importat
133 emit Transfer(_from, _to, _pizzaId);
134 _clearApproval(_to, _pizzaId);
135 }
136
137 /**
138 * Transferă în siguranță dreptul de proprietate asupra unui ID de token dat la o altă adresă
139 * Dacă adresa țintă este un contract, aceasta trebuie să implementeze `onERC721Received`,
140 * care este apelat la un transfer sigur și returnează valoarea magică
141 * `bytes4 (keccak256 (" onERC721Received(address,address,uint256, bytes)"))`;
142 * în caz contrar, transferul este anulat.
143 */
144 function safeTransferFrom(address from, address to, uint256 pizzaId)
145 public
146 {
147 // solium-disable-next-line arg-overflow
148 this.safeTransferFrom(from, to, pizzaId, "");
149 }
150
151 /**
152 * Transferă în siguranță dreptul de proprietate asupra unui ID de token dat la o altă adresă
153 * Dacă adresa țintă este un contract, aceasta trebuie să implementeze `onERC721Received`,
154 * care este apelat la un transfer sigur și returnează valoarea magică
155 * `bytes4 (keccak256 (" onERC721Received (address, address, uint256, bytes) "))`;
156 * în caz contrar, transferul este anulat.
157 */
158 function safeTransferFrom(
159 address from,
160 address to,
161 uint256 pizzaId,
162 bytes memory _data
163 ) public {
164 this.transferFrom(from, to, pizzaId);
165 require(_checkOnERC721Received(from, to, pizzaId, _data), "Must implement onERC721Received.");
166 }
167
168 /**
169 * Internal function to invoke `onERC721Received` on a target address
170 * The call is not executed if the target address is not a contract
171 */
172 function _checkOnERC721Received(
173 address from,
174 address to,
175 uint256 pizzaId,
176 bytes memory _data
177 ) internal returns (bool) {
178 if (!isContract(to)) {
179 return true;
180 }
181
182 bytes4 retval = IERC721Receiver(to).onERC721Received(
183 msg.sender,
184 from,
185 pizzaId,
186 _data
187 );
188 return (retval == _ERC721_RECEIVED);
189 }
190
191 // Burns a Pizza - destroys Token completely
192 // The `external` function modifier means this function is
193 // part of the contract interface and other contracts can call it
194 function burn(uint256 _pizzaId) external {
195 require(msg.sender != address(0), "Invalid address.");
196 require(_exists(_pizzaId), "Pizza does not exist.");
197 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
198
199 ownerPizzaCount[msg.sender] = SafeMath.sub(
200 ownerPizzaCount[msg.sender],
201 1
202 );
203 pizzaToOwner[_pizzaId] = address(0);
204 }
205
206 // Returns count of Pizzas by address
207 function balanceOf(address _owner) public view returns (uint256 _balance) {
208 return ownerPizzaCount[_owner];
209 }
210
211 // Returns owner of the Pizza found by id
212 function ownerOf(uint256 _pizzaId) public view returns (address _owner) {
213 address owner = pizzaToOwner[_pizzaId];
214 require(owner != address(0), "Invalid Pizza ID.");
215 return owner;
216 }
217
218 // Approves other address to transfer ownership of Pizza
219 function approve(address _to, uint256 _pizzaId) public {
220 require(msg.sender == pizzaToOwner[_pizzaId], "Must be the Pizza owner.");
221 pizzaApprovals[_pizzaId] = _to;
222 emit Approval(msg.sender, _to, _pizzaId);
223 }
224
225 // Returns approved address for specific Pizza
226 function getApproved(uint256 _pizzaId)
227 public
228 view
229 returns (address operator)
230 {
231 require(_exists(_pizzaId), "Pizza does not exist.");
232 return pizzaApprovals[_pizzaId];
233 }
234
235 /**
236 * Private function to clear current approval of a given token ID
237 * Reverts if the given address is not indeed the owner of the token
238 */
239 function _clearApproval(address owner, uint256 _pizzaId) private {
240 require(pizzaToOwner[_pizzaId] == owner, "Must be pizza owner.");
241 require(_exists(_pizzaId), "Pizza does not exist.");
242 if (pizzaApprovals[_pizzaId] != address(0)) {
243 pizzaApprovals[_pizzaId] = address(0);
244 }
245 }
246
247 /*
248 * Sets or unsets the approval of a given operator
249 * An operator is allowed to transfer all tokens of the sender on their behalf
250 */
251 function setApprovalForAll(address to, bool approved) public {
252 require(to != msg.sender, "Cannot approve own address");
253 operatorApprovals[msg.sender][to] = approved;
254 emit ApprovalForAll(msg.sender, to, approved);
255 }
256
257 // Tells whether an operator is approved by a given owner
258 function isApprovedForAll(address owner, address operator)
259 public
260 view
261 returns (bool)
262 {
263 return operatorApprovals[owner][operator];
264 }
265
266 // Takes ownership of Pizza - only for approved users
267 function takeOwnership(uint256 _pizzaId) public {
268 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
269 address owner = this.ownerOf(_pizzaId);
270 this.transferFrom(owner, msg.sender, _pizzaId);
271 }
272
273 // Checks if Pizza exists
274 function _exists(uint256 pizzaId) internal view returns (bool) {
275 address owner = pizzaToOwner[pizzaId];
276 return owner != address(0);
277 }
278
279 // Checks if address is owner or is approved to transfer Pizza
280 function _isApprovedOrOwner(address spender, uint256 pizzaId)
281 internal
282 view
283 returns (bool)
284 {
285 address owner = pizzaToOwner[pizzaId];
286 // Disable solium check because of
287 // https://github.com/duaraghav8/Solium/issues/175
288 // solium-disable-next-line operator-whitespace
289 return (spender == owner ||
290 this.getApproved(pizzaId) == spender ||
291 this.isApprovedForAll(owner, spender));
292 }
293
294 // Check if Pizza is unique and doesn't exist yet
295 modifier isUnique(string memory _name, uint256 _dna) {
296 bool result = true;
297 for (uint256 i = 0; i < pizzas.length; i++) {
298 if (
299 keccak256(abi.encodePacked(pizzas[i].name)) ==
300 keccak256(abi.encodePacked(_name)) &&
301 pizzas[i].dna == _dna
302 ) {
303 result = false;
304 }
305 }
306 require(result, "Pizza with such name already exists.");
307 _;
308 }
309
310 // Returns whether the target address is a contract
311 function isContract(address account) internal view returns (bool) {
312 uint256 size;
313 // Currently there is no better way to check if there is a contract in an address
314 // than to check the size of the code at that address.
315 // Consultă https://ethereum.stackexchange.com/a/14016/36603
316 // pentru mai multe detalii despre cum funcționează acest lucru.
317 // DE_FĂCUT Verifică din nou acest lucru înainte de lansarea Serenity, deoarece toate adresele vor fi
318 // contracte atunci.
319 // solium-disable-next-line security/no-inline-assembly
320 assembly {
321 size := extcodesize(account)
322 }
323 return size > 0;
324 }
325}
Afișează tot
Copiați

Referințe suplimentare

Consultaţi documentația Solidity și Vyper pentru a vedea o prezentare mai completă a contractelor inteligente:

A fost util acest articol?