Solidity tiek izmantots sarežģītu viedo līgumu izstrādei, kas paredzēti darbībai Ethereum blokķēdē. Šī valoda piedāvā unikālas stra­tē­ģi­jas, kas to atšķir no citām prog­ram­mē­ša­nas valodām.

Kas ir Solidity?

Solidity ir augsta līmeņa prog­ram­mē­ša­nas valoda, kas paredzēta viedo līgumu izveidei Ethereum blokķēdē. Viedie līgumi ir pa­šiz­pil­dā­mi līgumi, kas au­to­ma­ti­zē aktīvu apmaiņu starp pusēm. To īpaša iezīme ir tā, ka viedo līgumu izpildes no­dro­ši­nā­ša­nai nav ne­pie­cie­ša­mi star­pnie­ki.

Solidity avota kods tiek kompilēts bytecode un izvietots Ethereum blokķēdē kā viedais līgums. Pēc tam viedais līgums var tikt izpildīts jebkurā tīkla mezglā, un stāvoklis tiek saglabāts blokķēdē. Mēs parādām vienkārša līguma piemēru, kas modelē NFT tirdznie­cī­bas automātu:

pragma Solidity 0.8.7;
contract NFTVendingMachine {
    // Declare state variables
    address public owner;
    mapping (address => uint) public nftBalance;
    // Run on deployment
    constructor() {
        owner = msg.sender;
        nftBalance[address(this)] = 100;
    }
    // Allow the owner to restock the NFT balance
    function restock(uint amount) public {
        require(msg.sender == owner, "Only the owner can restock.");
        nftBalance[address(this)] += amount;
    }
    // Allow anyone to purchase NFTs
    function purchase(uint amount) public payable {
        require(msg.value >= amount * 1 ether, "You must pay at least 1 ETH per NFT");
        require(nftBalance[address(this)] >= amount, "Not enough NFTs in stock to complete this purchase");
        nftBalance[address(this)] -= amount;
        nftBalance[msg.sender] += amount;
    }
}
solidity

Kādām lie­to­jum­prog­ram­mām Solidity ir piemērots?

Solidity ir īpaši iz­strā­dāts, lai radītu iz­klie­dē­tas lie­to­jum­prog­ram­mas jeb DApps, kas darbojas uz Ethereum Virtual Machine (EVM). Viedie līgumi ir piemēroti, lai pār­val­dī­tu digitālos aktīvus, radītu de­cen­tra­li­zē­tas biržas un ieviestu bal­so­ša­nas sistēmas, kā arī citām lietām.

De­cen­tra­li­zē­tās finanses (DeFi)

Solidity tiek izmantots, lai iz­strā­dā­tu DeFi lie­to­jum­prog­ram­mas, piemēram, de­cen­tra­li­zē­tas biržas, kredītu un aizdevumu plat­for­mas, prog­no­zē­ša­nas tirgus un krip­to­va­lū­tas. DeFi ir kļuvis par vienu no po­pu­lā­rā­ka­jiem blokķēdes teh­no­lo­ģi­jas lie­to­ju­miem. Šajā procesā Solidity ir kļuvis par ne­aiz­stā­ja­mu rīku DeFi lie­to­jum­prog­ram­mu izstrādei Ethereum tīklā.

Ne­aiz­vie­to­ja­mi žetoni

Ne­aiz­vie­to­ja­mais žetons (NFT) kopš 2020. gada ir guvis lielu po­pu­la­ri­tā­ti. NFT ir unikāli digitāli aktīvi, kas tiek glabāti blokķēdē. Tie var būt digitāli mākslas darbi, sporta suvenīri vai artefakti no spēļu in­dus­tri­jas. Solidity tiek izmantots, lai izveidotu viedos līgumus, kas nodrošina NFT darbību.

Piegādes ķēdes pār­val­dī­ba

Solidity var izmantot, lai izveidotu viedos līgumus piegādes ķēžu uz­rau­dzī­bai un pār­val­dī­bai. Līgumi tiek izmantoti, lai au­to­ma­ti­zē­tu dažādus piegādes ķēdes procesus. Tie ietver preču kustības iz­se­ko­ša­nu, produktu au­ten­tis­ku­ma pārbaudi un maksājumu apstrādi starp pusēm.

Sa­ska­ņo­ša­nas sistēmas

Solidity var izmantot, lai izveidotu viedos līgumus, kas īsteno drošas un pār­re­dza­mas bal­so­ša­nas sistēmas blokķēdē. Līgumus var izmantot, lai no­dro­ši­nā­tu, ka balsis tiek skaitītas pareizi un bal­so­ša­nas process ir godīgs un pār­re­dzams.

Kādi ir Solidity priekš­ro­cī­bas un trūkumi?

Lai gan Solidity ir spēcīga valoda viedo līgumu izstrādei Ethereum blokķēdē, tai ir savas spe­ci­fis­kas priekš­ro­cī­bas un trūkumi, kurus iz­strā­dā­tā­jiem jāņem vērā, iz­strā­dā­jot viedos līgumus. Tomēr drošu viedo līgumu izstrāde prasa noteiktu prasmju līmeni un pie­sar­dzī­bu.

Kā ilus­trā­ci­ja zemāk ir redzams vieds līgums, kas darbojas kā melnais caurums. Jebkurš uz līgumu no­sū­tī­tais Ether tiek ne­at­grie­ze­nis­ki patērēts, un nav iespējams atgūt Ether vai veikt izmaksu:

// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.9.0;
// This contract swallows all Ether sent to it
contract Blackhole {
    event Received(address, uint);
    receive() external payable {
            emit Received(msg.sender, msg.value);
    }
}
solidity

Solidity priekš­ro­cī­bas

  • Elastība: Solidity ir daudz­pu­sī­ga valoda. To var izmantot, lai iz­strā­dā­tu dažādus viedos līgumus ar dažādiem lie­to­ša­nas ga­dī­ju­miem.
  • Drošība: Solidity tika izveidota, pievēršot uzmanību drošībai, iekļaujot tādas funkcijas kā piekļuves kontrole, izņēmumu apstrāde un kļūdu mehānismi, lai palīdzētu iz­strā­dā­tā­jiem izveidot drošus līgumus.
  • Saderība ar Ethereum: pašlaik Solidity ir vēlamā valoda viedo līgumu izstrādei Ethereum blokķēdē.
  • Atšķirīga kopiena: Liela blokķēdes iz­strā­dā­tā­ju kopiena strādā ar Solidity, kā rezultātā ir pieejams daudz resursu mācībām un problēmu ri­si­nā­ša­nai.

Solidity trūkumi

  • Mācību process: at­tīs­tī­tā­jiem, kuriem blokķēde un viedo līgumu izstrāde ir jauna joma, Solidity ir sa­lī­dzi­no­ši sarežģīts mācību process.
  • Ne­mai­nī­gums: Kad viedais līgums ir ieviests blokķēdē, to vairs nevar mainīt. Tāpēc iz­strā­dā­tā­jiem ir jābūt ārkārtīgi uz­ma­nī­giem, rakstot un testējot.
  • Formālās ve­ri­fi­kā­ci­jas trūkums: Solidity trūkst iebūvētu rīku formālai koda pār­ska­tī­ša­nai. Tāpēc iz­strā­dā­tā­jiem ir jāizmanto ārējie rīki, lai garantētu līgumu pre­ci­zi­tā­ti.
  • Ie­ro­be­žo­ti rīki: Solidity rīku eko­sis­tē­ma joprojām atrodas sākuma stadijā, kas var radīt problēmas ar in­teg­rē­ta­jām at­tīs­tī­bas vidēm (IDE), tes­tē­ša­nas sistēmām un citiem at­tīs­tī­bas rīkiem.

Kāda ir Solidity pamata sintakse?

Solidity ir ob­jek­to­rien­tē­ta prog­ram­mē­ša­nas valoda, kas iz­strā­dā­ta viediem līgumiem. Tā ir ie­dves­mo­ju­sies no Ja­vaScript, Python un C++. Valodas sintakse ir līdzīga Ja­vaScript, lai gan ar dažām in­te­re­san­tām īpatnībām.

Mainīgie Solidity

No pirmā acu uzmetiena Solidity mainīgo apstrāde var šķist līdzīga citām prog­ram­mē­ša­nas valodām. Tomēr būtiska atšķirība rodas no tā, ka Ethereum Virtual Machine (EVM) kalpo kā izpildes vide. Visas darbības EVM, ieskaitot datu uz­gla­bā­ša­nu, rada noteiktas “gāzes” izmaksas. Tāpēc prog­ram­mē­ša­nas laikā ir jāapsver darbības efek­ti­vi­tā­te un jānosaka, kā to var īstenot pēc iespējas efektīvāk.

Papildus pa­ras­ta­jām mai­nī­ga­jām lielumiem Solidity ir kon­stan­tes, kas jādefinē kom­pi­lā­ci­jas laikā. Kon­stan­tes prasa mazāk gāzes uz­gla­bā­ša­nai:

// Regular variable can be declared without defining
int a;
// Constant needs to be defined at declaration
int constant b = 51;
solidity

Tas pats attiecas uz immutable mai­nī­ga­jiem, jo tiem ir ne­pie­cie­šams mazāk gāzes un tos nevar mainīt pēc pie­šķir­ša­nas. Atšķirībā no constant mai­nī­ga­jiem, nemainīgo mainīgo pie­šķir­ša­na var tikt veikta darbības laikā.

Kon­tro­liz­tei­ku­mi Solidity

Kā im­pe­ra­tī­va prog­ram­mē­ša­nas valoda Solidity atbalsta pa­zīs­ta­mas kontroles ins­truk­ci­jas, piemēram, at­za­ro­ju­mus un cilpas. Parādām kodu, kas izvēlas lielāko no diviem skaitļiem, a un b:

int largerNumber = 0;
// If-else statement
if (a > b) {
    largerNumber = a;
} else {
        largerNumber = b;
}
solidity

for cilpa Solidity atbilst sintaksei, kas pazīstama no Ja­vaScript vai C++:

// Loop 10 times
for (int i = 0; i < 10; i++) {
    // …
}
solidity

while cilpa arī darbojas kā parasti. Mēs ap­vie­no­jam pār­trauk­ša­nas no­sa­cī­ju­mu ar skait­lis­ko skai­tī­tā­ja mainīgo:

bool continueLoop = true;
int counter = 0;
// Loop at most 10 times
while (continueLoop && counter < 10) {
    // …
    counter++;
}
solidity

Vien­kār­šie tipi Solidity

Solidity ir statiski tipizēta valoda, kas atbalsta prog­ram­mē­ša­nas valodās bieži sa­sto­pa­mos tipus. Vien­kār­šie tipi, kas pārstāv at­se­viš­ķas vērtības, ietver Boole’a tipus, skaitļus un virknes.

Booleani Solidity kartē ataino vērtības true un false. Tos var savienot, iz­man­to­jot pa­zīs­ta­mos Booleanu ope­ra­to­rus, un izmantot if iz­tei­ku­mos:

bool paymentReceived = true;
bool itemsStocked = true;
bool continueTransaction = paymentReceived && itemsStocked;
if (continueTransaction) {
    // ...
}
solidity

Solidity atbalsta plašu skait­lis­ko tipu klāstu. Veselos skaitļus var iedalīt pa­rak­stī­tos (int) un ne­pa­rak­stī­tos (uint) skaitļos, kur pēdējie var būt tikai pozitīvi. Turklāt skaitļa diapazonu var norādīt 8 bitu soļos, sākot no int8, caur int16 līdz int265:

uint8 smallNumber = 120;
int8 negativeNumber = -125;
int8 result = smallNumber + negativeNumber;
assert(result == -5)
solidity

Stingas Solidity tiek iz­man­to­tas gal­ve­no­kārt statusa ziņojumu ģe­ne­rē­ša­nai. Valoda atbalsta vien­kār­šās un dubultās pēdiņas, kā arī Unicode rakstzī­mes:

string message = 'Hello World';
string success = unicode"Transfer sent";
Solidity

Funkcijas Solidity

Funkcijas ir Soliditypa­ma­te­le­ments, tāpat kā lielākajā daļā prog­ram­mē­ša­nas valodu. Funkcijas de­fi­nī­ci­ja ir līdzīga Ja­vaScript, kur argumentu tipi ir jānorāda skaidri. Turklāt, lai norādītu return vērtību tipus, tiek izmantots at­slēg­vārds returns.

// Define a function
function addNumbers(int a, int b) returns (int) {
    return a + b;
}
solidity

Funkcijas iz­sauk­ša­na tiek veikta kā parasti:

// Call the function
int result = addNumbers(2, 3);
solidity

In­te­re­san­ti, ka līdzīgi kā no­sauk­tiem ar­gu­men­tiem, arī Solidity at­grie­ša­nas vērtības var nosaukt. Šajā situācijā pietiek ar at­bil­sto­šo mainīgo pie­šķir­ša­nu funkcijas ķermenī, un nav ne­pie­cie­ša­ma eks­pli­cī­ta at­grie­ša­na ar return:

function divideNumbers(int dividend, int divisor) returns (int quotient) {
    quotient = dividend / divisor;
    // No `return` necessary
}
solidity

Līdzīgi kā constant vai immutable mai­nī­ga­jiem, Solidity funkcijas var atzīmēt kā ne­mai­nī­gas. Šim nolūkam izmanto at­slēg­vār­dus view un pure. view funkcija nemaina stāvokli, bet pure funkcija papildus garantē, ka netiks lasīti stāvokļa mainīgie.

Viedie līgumi Solidity

Papildus standarta tipiem Solidity pazīst arī dažus viedlī­gu­mu spe­cia­li­zē­tos tipus. Pamata tips ir address un tas kartē Ethereum adreses. Adreses, kas ir payable, var saņemt pār­skai­tī­ju­mus Ether. Šim nolūkam payable adreses nodrošina balance() un transfer() metodes.

// Get address of this contract
address mine = address(this);
// Get payable external address
address payable other = payable(0x123);
// Transfer if balances fulfill conditions
if (other.balance < 10 && mine.balance >= 100) {
    other.transfer(10);
}
solidity

Pa­ma­to­jo­ties uz address tipu, contract tips pastāv kā centrāla valodas kons­truk­ci­ja. Līgumi aptuveni atbilst klasēm ob­jek­to­rien­tē­tās prog­ram­mē­ša­nas valodās. Tādējādi līgumi apvieno stāvokļa datus un funkcijas un aizsargā tos no ār­pa­sau­les. Līgumi atbalsta daudz­kār­tē­ju pār­man­to­ša­nu, kā tas ir zināms no Python vai C++.

Līgumi parasti sākas ar pragma rindu, kurā norādīta atļautā Solidity versija, kam seko faktiskā de­fi­nī­ci­ja:

// Make sure Solidity version matches
pragma Solidity >=0.7.1 <0.9.0;
// Contract definition
contract Purchase {
    // Public state variables
    address seller;
    address buyer;
    
    // View-function
    function getSeller() external view returns (address) {
        return seller;
    }
}
solidity

Viedie līgumi var definēt stāvokļa datus un funkcijas. Kā zināms no C++ un Java, katrā gadījumā var definēt vienu no trim piekļuves līmeņiem:

  • public: Mai­nī­ga­jam var piekļūt , lasot un rakstot no līguma. Turklāt view funkcija tiek au­to­mā­tis­ki ģenerēta kā getter ārējai lasīšanas piekļuvei.
  • internal: Mainīgais ir aiz­sar­gāts no ārējās piekļuves. Lasīšanas un rak­stī­ša­nas piekļuve ir iespējama no līguma, kā arī no man­to­ta­jiem līgumiem.
  • private: tāpat kā internal, bet nav piekļuves no man­to­ta­jiem līgumiem

Funkcijas var tālāk raksturot kā external. external funkcija darbojas kā daļa no līguma saskarnes un tiek izmantota ārējai piekļuvei. receive funkcija ētera sa­ņem­ša­nai ir labi zināms piemērs:

// Define without `function` keyword
receive() external payable {
    // Handle Ether
}
solidity

Mo­di­fi­ka­to­ri Solidity

Solidity ir in­te­re­san­ta valodas kons­truk­ci­ja mo­di­fi­ka­to­ru veidā, kas līdzinās Python de­ko­ra­to­riem. Līdzīgi kā Python, Solidity mo­di­fi­ka­to­ri tiek izmantoti, lai mainītu funkcijas iz­sauk­ša­nu. Tie bieži tiek izmantoti, lai no­dro­ši­nā­tu, ka pirms funkcijas izpildes tiek izpildīts konkrēts no­sa­cī­jums:

contract Sale {
    uint price;
    address payable owner;
    modifier onlyOwner {
        // Will throw error if called by anyone other than the owner
        require(
            msg.sender == owner,
            "Only owner can call this function."
        );
        // The wrapped function's body is inserted here
        _;
    }
    
    // `onlyOwner` wraps `changePrice`
    function changePrice(uint newPrice) public onlyOwner {
        // We'll only get here if the owner called this function
        price = newPrice;
    }
}
solidity

Darījumu pār­val­dī­ba ar Solidity

Solidity ir iebūvēta darījumu pār­val­dī­ba. To var izmantot, lai no­dro­ši­nā­tu, ka ētera pār­skai­tī­jums tiek pilnībā nokārtots vai vispār netiek nokārtots. Valoda saprot revert at­slēg­vār­du, kas izraisa darījuma “at­grie­ša­nu”. Ar error at­slēg­vār­du varat definēt savus kļūdu kodus:

// Custom error definition
error InsufficientPayment(uint256 paid, uint256 required);
// Contract representing a sale
contract Sale {
    uint price;
    // Purchase if enough ether transferred
    function purchase() public payable {
        if (msg.value < price) {
            revert InsufficientPayment(msg.value, price);
        }
        // Complete purchase
    }
}
solidity

Vēl viens bieži sastopams modelis ir require() funkcijas iz­man­to­ša­na. To var izmantot analogi revert:

// Using `require()` function
if (!condition) revert("Error message");
// Equivalent to
require(condition, "Error message");
solidity
Go to Main Menu