Ugrás a fő tartalomra
Change page

A okosszerződések anatómiája

Utolsó módosítás: @robertdosa(opens in a new tab), 2024. január 22.

Az okosszerződés egy olyan program, mely egy cím alatt fut az Ethereumon. Adatokból és függvényekből állnak, melyeket végre lehet hajtani bemenő tranzakciók által. Ez az áttekintés az okosszerződések felépítéséről szól.

Előfeltételek

Először tekintse meg az okosszerződésekről szóló cikket. Ez a dokumentum feltételezi, hogy már jártas a programozási nyelvekben, mint a JavaScript vagy a Python.

Adat

Minden szerződésadatot hozzá kell rendelni egy lokációhoz, mely lehet a storage vagy a memory. Költséges a tárhelyet módosítani egy okosszerződésben, tehát érdemes fontolóra venni, hogy hol legyen az adat.

Tárhely

Az állandó adatokat tárolásnak nevezzük, és állapotváltozók reprezentálják őket. Ezeket az értékeket permanensen a blokkláncon tároljuk. Deklarálnia kell a típust, hogy a szerződés számon tudja tartani, hogy mekkora tárhelyre lesz szüksége a blokkláncon az átfordításkor.

1// Solidity példa
2contract SimpleStorage {
3 uint storedData; // Állapotváltozó
4 // ...
5}
Másolás
1# Vyper példa
2storedData: int128
Másolás

Ha Ön programozott már objektumorientált nyelven, akkor a legtöbb típus valószínűleg ismerős lesz. Ugyanakkor az address típus új lesz, ha még csak most ismerkedik az Ethereum fejlesztéssel.

Az address típus egy Ethereum címet tud tárolni, mely 20 bájttal vagy 160 bittel egyenlő. Hexadecimális értéket ad vissza vezető 0x-szel.

A többi típus:

  • boolean
  • egész (integer)
  • fixpontos szám
  • fix méretű bájttömb
  • dinamikus méretű bájttömb
  • Racionális és egész szám literálok
  • String literálok
  • Hexadecimális literálok
  • Enum

További magyarázatért tekintse meg az alábbi dokumentumokat:

Memória

Memóriaváltozóknak nevezzük azokat az értékeket, melyek csak a szerződésfunkció végrehajtása alatt tárolódnak. Mivel nem kell őket permanensen a blokkláncon tárolni, így sokkal olcsóbb a használatuk.

Tudjon meg többet az EVM adattárolási módszeréről a Solidity dokumentációból(opens in a new tab) (a „Storage, Memory and the Stack” szekcióból).

Környezeti változók

A szerződésben meghatározott változók mellett van néhány speciális globális változó is. Elsősorban a blokklánccal vagy az aktuális tranzakcióval kapcsolatos információk nyújtására szolgálnak.

Példák:

Tul.ÁllapotváltozóLeírás
block.timestampuint256Jelenlegi blokk korszak időbélyege
msg.senderaddressAz üzenet küldője (jelenlegi hívás)

Függvények

A legegyszerűbben megfogalmazva, a függvények információkat kaphatnak vagy információkat állíthatnak be válaszul a bejövő tranzakciókra.

Kétfajta függvényhívás létezik:

  • internal – ezek nem okoznak EVM hívást
    • A belső (internal) függvényeket és állapotváltozókat csak belülről lehet elérni (vagyis a jelenlegi szerződésből vagy a származtatott szerződésekből)
  • external – ezek EVM hívást okoznak
    • A külső (external) függvények a szerződés felületének részei, mely azt jelenti, hogy meg lehet őket hívni más szerződésekből vagy tranzakciókon keresztül. Egy külső függvény f kódját nem lehet belülről meghívni (vagyis az f() nem működik, de a this.f() igen).

Ezenkívül lehetnek public vagy private típusúak is

  • a public függvényeket belülről lehet meghívni vagy kívülről üzenetek által
  • a private függvények csak abban a szerződésben láthatóak, amiben definiálták őket, a származtatott szerződésekben nem

A függvények és az állapotváltozók is lehetnek publikusak vagy privátak

Íme egy függvény, mely egy állapotváltozó értékét állítja be egy szerződésben:

1// Solidity példa
2function update_name(string value) public {
3 dapp_name = value;
4}
Másolás
  • A string típusú value paraméter kerül be a függvénybe: update_name
  • Ez public módon lett deklarálva, így mindenki hozzáfér
  • Nem view módon lett deklarálva, így módosíthatja a szerződésállapotot

Nézet (view) függvények

Ezek a függvények azt ígérik, hogy nem módosítják a szerződés adatainak állapotát. Általános példák a „getter” függvények – ezeket használhatja például egy felhasználó egyenlegének lekérdezésére.

1// Solidity példa
2function balanceOf(address _owner) public view returns (uint256 _balance) {
3 return ownerPizzaCount[_owner];
4}
Másolás
1dappName: public(string)
2
3@view
4@public
5def readName() -> string:
6 return dappName
Másolás

Mi számít állapotmódosításnak:

  1. Állapotváltozókba írás.
  2. Események kibocsátása(opens in a new tab).
  3. Másik szerződés létrehozás(opens in a new tab).
  4. selfdestruct használata.
  5. Ether küldése hívásokkal.
  6. Bármely függvény meghívása, mely nincs view vagy pure jelöléssel ellátva.
  7. Alacsony szintű hívások.
  8. Egysoros assembly használata, mely bizonyos opkódot tartalmaz.

Konstruktor függvények

A constructor csak egyszer fut le, amikor a szerződést először telepítik. Mint a constructor számos osztályalapú programozási nyelv esetében, ezek a függvények gyakran inicializálják az állapotváltozókat a meghatározott értékeikre.

1// Solidity példa
2// Inicializálja a szerződés adatait, beállítja az 'owner-t'
3// a szerződés létrehozó címére.
4constructor() public {
5 // Minden okosszerződés külső tranzakciókra hagyatkozik a függvényeik végrehajtására.
6 // az `msg` globális változó, mely az adott tranzakcióhoz tartozó adatot tartalmaz,
7 // mint a küldő címe és az ETH mennyisége a tranzakcióban.
8 // Több infó: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
9 owner = msg.sender;
10}
Összes megjelenítése
Másolás
1# Vyper példa
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
Másolás

Beépített függvények

A szerződésben meghatározott függvények és változók mellett van néhány speciális beépített függvény is. A legnyilvánvalóbb példák:

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

Ez lehetőséget ad a szerződéseknek, hogy ETH-t küldjenek más számláknak.

Függvények írása

A függvénynek szüksége van:

  • egy paraméterváltozóra és egy típusra (ha elfogad paramétereket)
  • a belső/külső deklarációra
  • a pure/view/payable deklarációra
  • a visszatérítési érték típusára (ha van visszatérítési értéke)
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}
Összes megjelenítése
Másolás

Egy kész szerződés nagyjából így nézne ki. Itt a constructor függvény biztosítja a dapp_name változó kezdeti értékét.

Események és naplózások

Az eseményeken keresztül tud kommunikálni az okosszerződés és a frontend vagy más feliratkozó alkalmazás. Amikor egy tranzakciót kibányásztak, az okosszerződések eseményeket bocsáthatnak ki és naplófájlokat írhatnak a blokkláncra, melyet a frontend fel tud dolgozni.

Jegyzetekkel ellátott példák

Íme néhány példa, amelyet Solidity-ben írtak. Ha szeretne megismerkedni a kóddal, akkor kipróbálhatja a Remixben(opens in a new tab).

Hello world

1// A Solidity verziószámát írja elő szemantikailag.
2// Több információ: https://solidity.readthedocs.io/en/v0.5.10/layout-of-source-files.html#pragma
3pragma solidity ^0.5.10;
4
5// Egy `HelloWorld` nevű szerződés definiálása.
6// A szerződés egy függvények és adatok (az állapota) gyűjteménye.
7// Telepítés után a szerződés egy bizonyos címen él az Ethereum blokkláncon.
8//További információ: https://solidity.readthedocs.io/en/v0.5.10/structure-of-a-contract.html
9contract HelloWorld {
10
11 // Deklarálja a `string` típusú `message` állapotváltozót.
12 // Az állapotváltozók olyan változók, melyeknek értékei permanensen tárolódnak a szerződés tárhelyén.
13 // A `public` kulcsszó lehetővé teszi a változó szerződésen kívüli elérését
14 // és függvényt hoz létre, mellyel más szerződések vagy kliensek le tudják kérdezni az értéket.
15 string public message;
16
17 // Más osztály alapú nyelvhez hasonlóan a konstruktor egy
18 // speciális függvény, mely csak egyszer fut le a szerződés létrehozáskor.
19 // A konstruktorokat az szerződés adatainak inicializálásra lehet használni.
20 // További információ: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#constructors
21 constructor(string memory initMessage) public {
22 // Az `initMessage` string paramétert fogadja el és beállítja
23 // a szerződés `message` tárhely változójába).
24 message = initMessage;
25 }
26
27 // Egy publikus függvény, mely egy string paramétert fogad el
28 // és frissíti a `message` tárhely változót.
29 function update(string memory newMessage) public {
30 message = newMessage;
31 }
32}
Összes megjelenítése
Másolás

Token

1pragma solidity ^0.5.10;
2
3contract Token {
4 // Egy `address` olyan, mint egy email cím - az Ethereum számlák beazonosítására szolgál.
5 // A címek okosszerződéseket vagy külső (felhasználói) számlákat jelölnek.
6 // Learn more: https://solidity.readthedocs.io/en/v0.5.10/types.html#address
7 address public owner;
8
9 // A `mapping` lényegében egy hash tábla adatszerkezet.
10 // Ez a `mapping` egy unsigned integert (a token egyenleget) rendel hozzá egy címhez (a token tartóhoz).
11 // További információ: https://solidity.readthedocs.io/en/v0.5.10/types.html#mapping-types
12 mapping (address => uint) public balances;
13
14 // Az eseményekkel lehet tevékenységet logolni a blokkláncon.
15 // Az Ethereum kliensek figyelhetik az eseményeket, hogy reagáljanak az szerződés állapotváltozásokra.
16 // További információ: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#events
17 event Transfer(address from, address to, uint amount);
18
19 // Inicializálja a szerződés adatot, beállítja az `owner`
20 // változót a szerződés létrehozó címére.
21 constructor() public {
22 // Minden okosszerződés külső tranzakciókra hagyatkozik a függvényeik végrehajtására.
23 // az `msg` globális változó, mely az adott tranzakcióhoz tartozó adatot tartalmaz,
24 // mint a küldő címe és az ETH mennyisége a tranzakcióban.
25 //További információ: https://solidity.readthedocs.io/en/v0.5.10/units-and-global-variables.html#block-and-transaction-properties
26 owner = msg.sender;
27 }
28
29 // Új tokeneket hoz létre és elküldi egy címre.
30 function mint(address receiver, uint amount) public {
31 // A `require` egy kontrol struktúra, mely bizonyos feltételek betartatására szolgál.
32 // Ha a `require` állítás `false` értéket ad, egy kivétel triggerelődik,
33 // mely visszaállít minden állapotváltozást a jelenlegi hívás alatt.
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 // A küldőnek elég tokennel kell rendelkeznie
49 require(amount <= balances[msg.sender], "Insufficient balance.");
50
51 // Beállítja a token a két cím token mennyiségét
52 balances[msg.sender] -= amount;
53 balances[receiver] += amount;
54
55 // Kibocsájtja a korábban definiált eseményt
56 emit Transfer(msg.sender, receiver, amount);
57 }
58}
Összes megjelenítése
Másolás

Egyedi digitális eszköz

1pragma solidity ^0.5.10;
2
3// Szimbólumokat importál be más fájlokból a jelenlegi szerződésbe.
4// Ebben az esetben egy pár segítő szerződést az OpenZeppelinről.
5// További információ: 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// Az `is` kulcsszót használjuk, hogy külső szerződések függvényeit és kulcsszavait örököltessük.
13// Ebben az esetben, `CryptoPizza` örököl az `IERC721` és az `ERC165` szerződésekből.
14// További információ: https://solidity.readthedocs.io/en/v0.5.10/contracts.html#inheritance
15contract CryptoPizza is IERC721, ERC165 {
16 // Az OpenZeppelin SafeMath könyvtárát használja aritmetikai számítások biztonságos elvégzésére.
17 // További információ: https://docs.openzeppelin.com/contracts/2.x/api/math#SafeMath
18 using SafeMath for uint256;
19
20 // A konstans állapotváltozók a Solidity-ben hasonlóak más nyelvekhez
21 // de a fordítás ideje alatt konstans kifejezésből kell hozzárendelni.
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 // További info: 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 // Átadja a Pizza tulajdonjogot és másik címnek
122 function transferFrom(address _from, address _to, uint256 _pizzaId) public {
123 require(_from != address(0) && _to != address(0), "Invalid address.");
124 require(_exists(_pizzaId), "Pizza does not exist.");
125 require(_from != _to, "Cannot transfer to the same address.");
126 require(_isApprovedOrOwner(msg.sender, _pizzaId), "Address is not approved.");
127
128 ownerPizzaCount[_to] = SafeMath.add(ownerPizzaCount[_to], 1);
129 ownerPizzaCount[_from] = SafeMath.sub(ownerPizzaCount[_from], 1);
130 pizzaToOwner[_pizzaId] = _to;
131
132 // Kibocsájt egy eseményt, mely az importált IERC721 szerződésben van definiálva
133 emit Transfer(_from, _to, _pizzaId);
134 _clearApproval(_to, _pizzaId);
135 }
136
137 /**
138 * Biztonságosan átadja a egy adott token ID tulajdonjogát egy másik címnek
139 * Ha a cél cím egy szerződés, akkor az `onERC721Received`-nek implementálva kell lennie,
140 * mely egy biztonságos átadáskor meghívódik és visszaadja a bűvös értéket
141 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
142 * ellenkező esetben a transfer visszafordul.
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 * Biztonságosan átadja a egy adott token ID tulajdonjogát egy másik címnek
153 * Ha a cél cím egy szerződés, akkor az `onERC721Received`-nek implementálva kell lennie,
154 * mely egy biztonságos átadáskor meghívódik és visszaadja a bűvös értéket
155 * `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`;
156 * ellenkező esetben a transfer visszafordul.
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 // Lásd https://ethereum.stackexchange.com/a/14016/36603
316 // hogy hogyan működik ez.
317 // TODO A Serenity release előtt ellenőrizni, mivel azután minden cím
318 // szerződés lesz.
319 // solium-disable-next-line security/no-inline-assembly
320 assembly {
321 size := extcodesize(account)
322 }
323 return size > 0;
324 }
325}
Összes megjelenítése
Másolás

További olvasnivaló

Tekintse meg a Solidity és a Vyper dokumentációit az okosszerződések teljesebb áttekintésért:

Hasznosnak találta a cikket?