Solidity Tutorial: En introduktion til soliditetsprogrammering for begyndere

Vejledning om soliditet

Soliditet er et objektorienteret sprog på højt niveau til udvikling af dApps (decentrale applikationer) på Ethereum blockchain.

En blockchain er et peer-to-peer-netværk af computere, kaldet noder, der deler alle data og koden i netværket.

Så hvis du er en enhed tilsluttet blockchain, er du en node i netværket, og du taler med alle de andre computernoder i netværket (vi vil tale om, hvordan du konfigurerer Ethereum-node på din lokale maskine i senere tutorials).

Du har nu en kopi af alle data og koden på blockchain. Der er ikke længere behov for centrale servere.

Hvad er Ethereum?

Ethereum er på sin enkleste måde en åben softwareplatform baseret på blockchain-teknologi, der gør det muligt for udviklere at opbygge og implementere decentrale applikationer..

Mens Bitcoin blockchain bruges til at spore ejerskab af digital valuta (bitcoins), fokuserer Ethereum blockchain på at køre koden for decentrale applikationer.

I Ethereum-blockchain arbejder minearbejdere i stedet for minedrift for bitcoin for at tjene Ether, en type kryptotoken, der brænder netværket. Ud over en omsættelig kryptokurrency bruges Ether også af applikationsudviklere til at betale for transaktionsgebyrer og tjenester på Ethereum-netværket.

Der er en anden type token, der bruges til at betale minearbejdere gebyrer for at medtage transaktioner i deres blok, det kaldes gas, og enhver smart kontraktudførelse kræver, at en bestemt mængde gas sendes sammen med den for at lokke minearbejdere til at sætte den ind blockchain.

Startende med det grundlæggende

Soliditets kode er indkapslet i kontrakter.

Ethereum blockchain giver os mulighed for at udføre kode med Ethereum Virtual Machine (EVM) på blockchain med noget, der kaldes en smart kontrakt.

Smart kontrakter er, hvor al forretningslogik i vores applikation lever – alle variabler og funktioner hører til en kontrakt, og dette vil være udgangspunktet for alle dine projekter.

Smarte kontakter er skrevet på et programmeringssprog kaldet Solidity, der ligner en blanding af Javascript og C.

Remix IDE

Remix er onlineværktøj, der giver dig mulighed for at skrive Smart Soliditets-kontrakter, derefter implementere dem og køre den.

Bare gå til https://remix.ethereum.org fra din browser, og vi kan begynde at kode.

Som du kan se, kan du vælge mellem Solidity og Vyper. Begge er sprog til at skrive smarte kontrakter, Vyper er pythonlignende og soliditet er javascript-lignende.

Begge kan kompilere til EVM-bytecode, ligesom Javascript og Typescript. Vi vælger Solidity.

På venstre side er der filudforsker. Som standard er der to .sol-filer, bare for at demonstrere grundlæggende syntaks (ballot.sol er smart kontrakt, ballot_test.sol er script til test af den smarte kontrakt).

Du skal bare klikke på plusknappen, så kan vi begynde at kode vores første smarte kontrakt.

Al soliditetskildekode skal starte med en “version pragma” – en erklæring om den version af Solidity-kompilatoren, som denne kode skal bruge. Dette er for at forhindre problemer med fremtidige compilerversioner, der potentielt introducerer ændringer, der bryder din kode.

Det ser sådan ud:

pragmasoliditet ^ 0.4.25;

(for Solidity-versionen over 0.4.25)

eller

pragma soliditet >= 0,5,0 < 0,6,0;

(til Solidity-versionen mellem 0.5.0 og 0.6.0)

Derefter opretter du din kontrakt ved at skrive reserveret ord kontrakt og navnet på din .sol-fil (Det er vigtigt, at kontraktnavnet matcher filens navn, vi vil diskutere hvorfor senere). I vores tilfælde,

kontrakt MyFirstContract {

}

Lad os kompilere det. Du skal bare navigere til den kompileringsfane til venstre og klikke på den store kompileringsknap. Hvis der er noget galt med koden, vil du se fejl og advarsler her (vær medfølende med soliditet, det er stadig “ungt sprog”).

Med vores nuværende kontrakt er alt i orden, fordi vi virkelig ikke har gjort noget.

Nu vil jeg generere fejl med vilje bare for at vise dig noget. Du kan manuelt vælge kompilator fra rullemenuen.

Lad os f.eks. Vælge version 0.4.26. Kompilér det igen. Nu vil du se en ‘Compiler endnu ikke indlæst’ fejl.

Dette skyldes, at vi med pragma specificerede at arbejde med compilerversioner over 0.5.0. Skift bare compilerversion igen, så er fejlen væk.

Okay, lad os kode nu!

Vi starter med en simpel ‘Hello world’-kode og får og indstiller funktioner, bare for at blive mere fortrolig med syntaksen.

En kontrakt i form af soliditet er en samling af kode (dens funktioner) og data (dens tilstand), der ligger på en bestemt adresse på Ethereum blockchain.

Lad os først definere tilstandsvariabel kaldet meddelelse for eksempel, og dens type vil være streng.

Vores get-funktion returnerer værdien af ​​vores variable meddelelse, og den indstillede funktion tildeler en ny værdi til vores variable meddelelse.

Sådan skriver du funktioner?

Først reserveret ord fungere derefter navnet på en bestemt funktion og parametre og derefter .

funktion myFunction () returnerer (bool) {

returner sandt

}

Funktioner kan være offentlig eller privat. Hvis en funktion er offentlig, kan den kaldes uden for kontrakten. Hvis en funktion er privat, har den et begrænset omfang og kan kun kaldes fra dens nuværende kontrakt (fra f.eks. En anden funktion).

Her er listen over alle funktionssynlighedsspecifikatorer:

  • offentlig: synlig eksternt og internt (opretter en getter-funktion til lagring / tilstandsvariabler)
  • privat: kun synlig i den nuværende kontrakt
  • ekstern: kun synligt eksternt (kun for funktioner) – dvs. kan kun kaldes besked (via denne.func)
  • indre: kun synlig internt

Funktioner kan være ren, udsigt, eller betales. Hvis en funktion ikke skriver nogen data på blockchain, anbefales det meget at blive vist, fordi visningsfunktioner ikke koster noget gas.

Her er listen over alle funktionsmodifikatorer (der er også modifikatorer for tilstandsvariabler, begivenheder og begivenhedsargumenter, men det vil tale om dem senere):

  • ren: Tillader ændring eller adgang til tilstand.
  • udsigt: Tillader ændring af tilstand.
  • betales: Tillader dem at modtage Ether sammen med et opkald.

Hvis Funktion returnerer en værdi, skal du angive det med reserveret ord vender tilbage og derefter i almindelige parenteser for at angive, hvilken type der fungerer, returnerer. I vores tilfælde vil det være streng (fordi vi returnerer vores variable besked, som er streng)

Hvis funktionen ikke returnerer nogen værdi, er der ikke behov for det vender tilbage udmelding.

For at få adgang til en tilstandsvariabel behøver du ikke præfikset det her. som det er almindeligt på andre sprog.

På grund af dette er en almindelig praksis at skrive funktionsargumenter med understregning af syntaks (_besked). Denne konvention kom fra Javascript, hvor private metoder og variabler starter med _.

For at være klar fungerer din kode fint og uden understregning, men den er renere med dem.

Du vil bemærke reserveret ord hukommelse i vores kode. Hvis du skriver vores kode uden hukommelse og indstiller pragma til en version under 0,5. * Det fungerer fint, men når du ændrer din compiler til over 0,5. * EVM genererer kompileringsfejl.

Hvorfor sker dette??

Nå, Ethereum Virtual Machine har tre områder, hvor den kan gemme varer.

  • Den første er opbevaring, hvor alle kontraktstatusvariabler findes. Hver kontrakt har sin egen opbevaring, og den er vedvarende mellem funktionsopkald og ret dyr i brug.
  • Den anden er hukommelse, dette bruges til at holde midlertidige værdier. Det slettes mellem (eksterne) funktionsopkald og er billigere at bruge.
  • Den tredje er stak, som bruges til at indeholde små lokale variabler. Det er næsten gratis at bruge, men kan kun indeholde en begrænset mængde værdier.

For næsten alle typer kan du ikke angive, hvor de skal opbevares, fordi de kopieres hver gang de bruges.

Men når du arbejder med arrays eller structs, og fra de nyeste versioner med strings også, vil compileren tvinge dig til at specificere butiksområde.

Så vores kode ser nu sådan ud:

pragmasoliditet ^ 0,5,0;

kontrakt MyFirstContract {

streng besked;

funktion get () offentlig visning returnerer (strenghukommelse) {

returnere besked;

}

funktionssæt (strenghukommelse _meddelelse) offentlig {

besked = _ besked;

}

}

Bemærk, at nogle Solidity-udviklere opdeler disse synlighedsspecifikationer i separate linjer for at gøre kode renere. Så vores get-funktion kan skrives således:

funktion få ()

offentlig

udsigt

returnerer (streng)

{

returnere besked;

}

Det er virkelig op til dig, hvordan du vælger at skrive dine funktioner.

Lad os udarbejde vores kontrakt nu og teste den.

For at kompilere det skal du bare gentage trinene nedenfra (Kompilér .sol knap eller cmd / ctrl + S fra tastaturet, og det kompileres automatisk igen)

For at se, hvordan det fungerer (hvis kompilering ikke genererer fejl), skal du implementere din kontrakt.

For at gøre det skal du navigere til fanen Implementering fra venstre, for miljø skal du vælge JavaScriptVM og trykke på Implementeringsknap.

Efter implementeringen kan vi nu se metoder fra vores kontrakt. Lad os bare fokusere på den del af skærmen nu.

Du kan se, at der er to knapper (get & sæt) til vores to offentlige funktioner. Hvis nogen af ​​disse var private, ville vi ikke se det her.

Hvis vi klikker på get-knappen, udfører EVM vores get-funktion.

Lad os se, hvordan det fungerede.

Vi har en tom streng. Ikke fantastisk, ikke forfærdeligt. Men hvorfor? Nå, fordi vi ikke initialiserede vores meddelelsesvariabel fra starten.

Bare en hurtig pause. Jeg vil have dig til at introducere til Remix Terminal. Det er under kodeditor, og her kan du spore alle dine transaktioner, for at se om de udføres med succes eller ej, for at debugge dem, se detaljer (transaktionshash osv.) Og mere.

Indtil videre har vi to succesrige transaktioner. Den ene er Contract Deployment, og det koster os ether (men rolig, vi er i editor nu er alt virtuelt) og det andet er Call of our udsigt fungere.

Ok, lad os gå tilbage nu. Hvad vil der ske, hvis vi kalder sætfunktionen nu?

Vi er nødt til at sende et argument _besked (f.eks. “Hello World”) og trykke på transact-knappen for at udføre funktionen. Du kan spore succesen med transaktionen i Terminal.

Lad os nu ringe til funktionen igen. Nu returnerer det vores budskab.

Lad os foretage nogle forbedringer af vores kode. Vi initialiserede ikke vores variable besked. Lad os gøre det.

kontrakt MyFirstContract {

streng besked = "Hej Verden!";

funktion get () offentlig visning returnerer (strenghukommelse) {

returnere besked;

}

funktionssæt (strenghukommelse _meddelelse) offentlig {

besked = _ besked;

}

}

Bemærk, at meddelelsen nu er “Hej verden!”, Og når vi ringer, få funktionen for første gang, returnerer den ikke tom streng.

For at teste dette skal vi kompilere vores kontrakt (cmd / ctrl + S).

Derefter for at implementere det igen. Vi er nødt til at oprette en ny instans af kontrakt (på grund af de ændringer, vi har foretaget) og offentliggøre den på blockchain.

Slet bare den tidligere version fra editoren (selvfølgelig ikke fra vores virtuelle blockchain), og tryk på knappen Implementér igen. Lad os kalde vores get-funktion nu.

Pæn! Lad os kalde indstillingsfunktionen nu.

Og kom igen.

Fedt nok.

Lad os nu gøre vores budskab a konstant.

Vores kode nu:

pragmasoliditet ^ 0,5,0;

kontrakt MyFirstContract {

streng konstant besked = "Hej Verden!";

funktion get () offentlig visning returnerer (strenghukommelse) {

returnere besked;

}

funktionssæt (strenghukommelse _meddelelse) offentlig {

besked = _ besked;

}

}

Når vi prøver at kompilere det, får vi fejl i vores sætfunktion. Det skyldes, at man ikke kan ændre en konstantværdi.

Vi skal bare slippe af med den konstante nu.

At initialisere variabler som dette er ikke en fejl, men det er meget bedre, hvis vi gør det i konstruktør. Du kan skrive konstruktør i soliditet med:

konstruktør () offentlig {

// gør noget…

}

Constructor er bare en anden funktion, der kaldes til under implementering af smart kontrakt. Vores kode ser lidt anderledes ud, men den fungerer ens.

pragmasoliditet ^ 0,5,0;

kontrakt MyFirstContract {

streng besked;

konstruktør () offentlig {

besked = "Hej Verden!";

}

funktion get () offentlig visning returnerer (strenghukommelse) {

returnere besked;

}

funktionssæt (strenghukommelse _meddelelse) offentlig {

besked = _ besked;

}

}

Du kan kompilere det igen og teste det, hvis du vil.

Endelig kan man ændre synligheden af ​​tilstandsvariabler. Hvis du laver dine tilstandsvariabler offentlig det betyder, at man kan kræve deres værdier uden for kontrakten.

Soliditet vil for hver offentlig statsvariabel gøre en metode med samme navn, som kan kaldes som en almindelig funktion (lidt som getter-funktion).

Dette betyder, at vi kan slippe af med vores get-funktion, bare erklære variabel besked som offentlig, og vores kode fungerer det samme, det vil være meget renere, og det koster os mindre at distribuere den en dag til Main Network.

Jo større koden er, jo mere gas er der behov for at udføre den, og omkostningerne ved at køre vores dApp stiger.

Når vi udvikler smarte kontrakter, skal vi være:

  • effektiv – den forbrugte gashastighed skal være lav
  • præcis – når du først har implementeret smart kontrakt, kan den ikke ændres, og den er offentlig 24 / 7h, hver eneste linje kode (forestil dig en hacker, der finder en fejl og kan udnytte din dApp)

Vores sidste kode for i dag ser sådan ud:

pragmasoliditet ^ 0,5,0;

kontrakt MyFirstContract {

streng offentlig besked;

konstruktør () offentlig {

besked = "Hej Verden!";

}

funktionssæt (strenghukommelse _meddelelse) offentlig {

besked = _ besked;

}

}

Lad os implementere det og teste det.

Du kan se meddelelsesknappen. Det oprettes, fordi vores tilstandsvariabel er offentlig.

Hvis vi kalder det, skal det returnere os en værdi, der initialiseres gennem konstruktør (det er “Hej verden!”).

Pæn. Lad os teste sæt funktion nu.

Sådan lærer du soliditet?

Soliditet i sig selv er ret simpelt sprog, men for at være en god soliditetsudvikler skal man forstå, hvordan alt fungerer på Ethereum.

  • Soliditet er programmeringssprog på højt niveau med syntaks svarende til ECMAScript (javascript).
  • Den kompileres til EVM bytecode, noget kun EVM kan forstå.
  • Compileren kaldes Solc.

Lad os tage denne enkle kontrakt som eksempel:

pragmasoliditet ^ 0,5,0;

kontrakteksempel {

uint a = 10 + 5;

}

Så simpelt er det. Lad os nu sammensætte det. Hvis vi går til kontraktoplysninger i terminalen, kan vi se en masse information.

I dette tilfælde er den kompilerede kode:

0x6080604052600f600055348015601457600080fd5b5060358060226000396000f3fe6080604052600080fdfea165627a7a72305820bf75c57b7d8745a79baee513ead21a9eb8b075896f8e4c591

Disse lange værdier er hexadecimal repræsentation af den endelige kontrakt, også kendt som bytecode. EVM forstår kun bytecode.

Men hvis noget går galt, sidder vi fast med en eller anden fejl, for eksempel kan man ikke fejle bytecode.

Opkoder

Sprog over bytekode er opcode. Opcode er programmeringssprog på lavt niveau. Solidity og Opcode er f.eks. C og Assembly Language.

Så når vi har brug for at debugge en mislykket transaktion, fejler vi opcode.

Én ting du skal vide om soliditet og fejlretning – det er meget svært. Men ikke umuligt, så lad os dykke ned i det.

Dette er opcode for vores eksempelkontrakt:

0 PUSH1 60

02 PUSH1 40

04 MSTORE

05 PUSH1 0f

07 PUSH1 00

09 BUTIK

10 CALLVALUE

11 DUP1

12 ISZERO

13 PUSH1 14

15 JUMPI

16 PUSH1 00

18 DUP1

19 TILBAGE

20 JUMPDEST

21 POP

22 PUSH1 35

24 DUP1

25 PUSH1 22

27 PUSH1 00

29 KODEKOPIERING

30 PUSH1 00

32 TILBAGE

33 UGYLDIG

34 PUSH1 80

36 PUSH1 40

38 MSTORE

39 PUSH1 00

41 DUP1

42 TILBAGE

43 UGYLDIG

44 LOG1

45 PUSH6 627a7a723058

52 SHA3

53 UGYLDIG

54 PUSH22 c57b7d8745a79baee513ead21a9eb8b075896f8e4c59

77 UGYLDIG

78 DUP10

79 OG

80 JUMPI

81 UGYLDIG

82 BALANCE

83 PUSH29 750029

Opkoder er de menneskelige læsbare instruktioner på lavt niveau i programmet. Alle opkoder har deres hexadecimale modstykker, f.eks MSTORE er 0x52.

EVM er stakmaskine. Det er baseret på LIFO-struktur (Last In First Out). For at forenkle, forestil dig at stable skiver brød i en mikrobølgeovn, den sidste skive du lægger i er den FØRSTE du tager ud.

I normal aritmetik skriver vi vores ligning på denne måde:

10 + 2 * 2

og svaret er 14, fordi vi multiplicerer før tilføjelse.

I en stakmaskine fungerer det i LIFO-princip:

2 2 * 10 +

Det betyder, læg 2 i stakken først efterfulgt af en anden 2, derefter efterfulgt af multiplikationshandling. Resultatet er 4 sidder oven på stakken. Tilføj nu et nummer 10 oven på 4, og til sidst tilføj de 2 tal sammen. Den endelige værdi af stakken bliver 14.

Handlingen med at lægge data i stakken kaldes PUSH-instruktionen, og handlingen med at fjerne data fra stakken kaldes POP-instruktionen. Det er indlysende, at den mest almindelige opkode, vi ser i vores eksempel ovenfor, er PUSH1, hvilket betyder at sætte 1 byte data i stakken.

Så denne instruktion:

PUSH1 0x60

betyder at sætte en 1 byteværdi på “0x60” i stakken. Tilfældigvis er den hexadecimale værdi for PUSH1 tilfældigvis også “0x60”. Fjernelse af det ikke-obligatoriske “0x”, vi kunne skrive denne logik i bytekode som “6060”.

Lad os gå lidt længere.

PUSH1 0x60 PUSH1 0x40 MSTORE

MSTORE (0x52) modtager 2 indgange og producerer ingen output. Opkoderne ovenfor betyder:

PUSH1 (0x60): sæt 0x60 i stakken.

PUSH1 (0x40): sæt 0x40 i stakken.

MSTORE (0x52): tildel 0x60 hukommelsesplads og flyt til 0x40 position.

Den resulterende bytekode er:

6060604052

Faktisk ser vi altid dette magiske nummer “6060604052” i begyndelsen af ​​enhver soliditet-bytecode, fordi det er hvordan den smarte kontrakt bootstrap.

For yderligere at komplicere sagen kan 0x40 eller 0x60 ikke fortolkes som det reelle tal 40 eller 60. Da de er hexadecimale, svarer 40 faktisk til 64 (16¹ x 4) og 60 svarer til 96 (16¹ x 6) i decimal.

Kort sagt, hvad “PUSH1 0x60 PUSH1 0x40 MSTORE” gør, er at tildele 96 byte hukommelse og flytte markøren til begyndelsen af ​​den 64. byte. Vi har nu 64 byte til ridseplads og 32 byte til midlertidig hukommelseslagring.

I EVM er der 3 steder at gemme data. For det første i stakken. Vi har lige brugt PUSH-opkoden til at gemme data der som beskrevet i eksemplet ovenfor.

For det andet i hukommelsen (RAM), hvor vi bruger MSTORE-opkoden, og endelig i disklageret, hvor vi bruger SSTORE til at gemme dataene. Den gas, der kræves for at lagre data til lagring, er den dyreste, og det er billigst at gemme data til stabling.

Nu er det godt tid at gå tilbage til vores soliditetskode fra denne vejledning og at sammenfatte det, vi lærte om reserveret ord hukommelse og hvordan kompilator tvinger os til at specificere hvordan vi f.eks. gemmer strenge.

Vi har kun dækket det grundlæggende ved bytecode og et par opcodes.

Vi behøver ikke at kende opcodes for at begynde at skrive smart kontrakt!

På den anden side er EVM-fejlhåndtering stadig meget primitiv, og det er praktisk at se på opkoder, når tingene går galt.

Konklusion

Denne første lektion har lidt mere teori end egentlig kodning, men det er meget vigtigt for begyndere at vide, hvordan ting fungerer på Ethereum. I de næste selvstudier skriver vi noget mere interessant kode og lærer, hvordan vi implementerer vores eget token på Ethereum blockchain.

Indtil da &# 128075;

Mike Owergreen Administrator
Sorry! The Author has not filled his profile.
follow me