Solidität - Kurzanleitung

Solidity ist eine vertragsorientierte Programmiersprache auf hoher Ebene für die Implementierung intelligenter Verträge. Die Solidität wird stark von C ++, Python und JavaScript beeinflusst und wurde speziell für die Ethereum Virtual Machine (EVM) entwickelt.

Solidity ist statisch typisiert, unterstützt Vererbung, Bibliotheken und komplexe benutzerdefinierte Programmiersprachen.

Mit Solidity können Sie Verträge für Zwecke wie Abstimmungen, Crowdfunding, Blindauktionen und Brieftaschen mit mehreren Signaturen erstellen.

Was ist Ethereum?

Ethereum ist ein dezentrales dh. Blockchain-Plattform, auf der intelligente Verträge ausgeführt werden, dh Anwendungen, die genau wie programmiert ausgeführt werden, ohne dass Ausfallzeiten, Zensur, Betrug oder Eingriffe Dritter möglich sind.

Die Ethereum Virtual Machine (EVM)

Die Ethereum Virtual Machine, auch als EVM bekannt, ist die Laufzeitumgebung für intelligente Verträge in Ethereum. Die virtuelle Maschine von Ethereum konzentriert sich auf die Bereitstellung von Sicherheit und die Ausführung von nicht vertrauenswürdigem Code durch Computer auf der ganzen Welt.

Das EVM hat sich auf die Verhinderung von Denial-of-Service-Angriffen spezialisiert und stellt sicher, dass Programme keinen Zugriff auf den Status des jeweils anderen haben, sodass die Kommunikation ohne potenzielle Interferenzen hergestellt werden kann.

Die virtuelle Maschine von Ethereum wurde als Laufzeitumgebung für intelligente Verträge auf Basis von Ethereum entwickelt.

Was ist ein intelligenter Vertrag?

Ein intelligenter Vertrag ist ein Computerprotokoll, das die Aushandlung oder Erfüllung eines Vertrags digital erleichtern, überprüfen oder durchsetzen soll. Intelligente Verträge ermöglichen die Durchführung glaubwürdiger Transaktionen ohne Dritte. Diese Transaktionen sind nachverfolgbar und irreversibel.

Das Konzept der intelligenten Verträge wurde erstmals 1994 von Nick Szabo vorgeschlagen. Szabo ist ein Rechtswissenschaftler und Kryptograf, der dafür bekannt ist, die Grundlagen für die digitale Währung zu legen.

Wenn Sie Smart Contract derzeit nicht verstehen, werden wir später näher darauf eingehen.

In diesem Kapitel wird erläutert, wie Sie den Solidity-Compiler auf einem CentOS-Computer einrichten können. Wenn Sie keinen Linux-Computer haben, können Sie unseren Online-Compiler für kleine Verträge und zum schnellen Erlernen von Solidity verwenden.

Methode 1 - npm / Node.js.

Dies ist der schnellste Weg, um den Solidity-Compiler auf Ihrem CentoS-Computer zu installieren. Wir haben folgende Schritte, um Solidity Compiler zu installieren -

Installieren Sie Node.js.

Stellen Sie zunächst sicher, dass auf Ihrem CentOS-Computer node.js verfügbar ist. Wenn es nicht verfügbar ist, installieren Sie es mit den folgenden Befehlen:

# First install epel-release
$sudo yum install epel-release

# Now install nodejs
$sudo yum install nodejs

# Next install npm (Nodejs Package Manager )
$sudo yum install npm

# Finally verify installation
$npm --version

Wenn alles installiert wurde, sehen Sie eine Ausgabe wie diese -

3.10.10

Installieren Sie solc

Sobald Sie den Node.js-Paketmanager installiert haben, können Sie den Solidity-Compiler wie folgt installieren:

$sudonpm install -g solc

Der obige Befehl installiert das Programm solcjs und stellt es global im gesamten System zur Verfügung. Jetzt können Sie Ihren Solidity-Compiler testen, indem Sie den folgenden Befehl eingeben:

$solcjs-version

Wenn alles gut geht, wird dies wie folgt gedruckt:

0.5.2+commit.1df8f40c.Emscripten.clang

Jetzt können Sie solcjs verwenden, das weniger Funktionen als der Standard-Solidity-Compiler bietet, aber einen guten Ausgangspunkt bietet.

Methode 2 - Docker Image

Sie können ein Docker-Image ziehen und es verwenden, um mit der Solidity-Programmierung zu beginnen. Es folgen die einfachen Schritte. Es folgt der Befehl zum Abrufen eines Solidity Docker-Images.

$docker pull ethereum/solc:stable

Sobald ein Docker-Image heruntergeladen wurde, können wir es mit dem folgenden Befehl überprüfen.

$docker run ethereum/solc:stable-version

Dies wird etwas wie folgt drucken -

$ docker run ethereum/solc:stable -version

solc, the solidity compiler commandlineinterfaceVersion: 0.5.2+commit.1df8f40c.Linux.g++

Methode 3: Installation von Binärpaketen

Wenn Sie bereit sind, einen vollwertigen Compiler auf Ihrem Linux-Computer zu installieren, besuchen Sie bitte die offizielle Website Installieren des Solidity Compilers.

Solidity-Quelldateien können eine beliebige Anzahl von Vertragsdefinitionen, Importanweisungen und Pragma-Anweisungen enthalten.

Beginnen wir mit einer einfachen Quelldatei von Solidity. Das folgende Beispiel zeigt eine Solidity-Datei:

pragma solidity >=0.4.0 <0.6.0;
contract SimpleStorage {
   uint storedData;
   function set(uint x) public {
      storedData = x;
   }
   function get() public view returns (uint) {
      return storedData;
   }
}

Pragma

Die erste Zeile ist eine Pragma-Direktive, die besagt, dass der Quellcode für Solidity Version 0.4.0 oder für neuere Versionen geschrieben wurde, die die Funktionalität bis Version 0.6.0 nicht beeinträchtigen, diese jedoch nicht einschließen.

Eine Pragma-Direktive ist immer lokal für eine Quelldatei. Wenn Sie eine andere Datei importieren, wird das Pragma aus dieser Datei nicht automatisch auf die importierende Datei angewendet.

Ein Pragma für eine Datei, die nicht früher als Version 0.4.0 kompiliert wird und auch nicht auf einem Compiler ab Version 0.5.0 funktioniert, wird wie folgt geschrieben:

pragma solidity ^0.4.0;

Hier wird die zweite Bedingung mit ^ hinzugefügt.

Vertrag

Ein Solidity-Vertrag ist eine Sammlung von Code (seine Funktionen) und Daten (sein Status), die sich an einer bestimmten Adresse in der Ethereumblockchain befinden.

Die Zeile uintstoredData deklariert eine Statusvariable namens savedData vom Typ uint, und die Funktionen set und get können zum Ändern oder Abrufen des Werts der Variablen verwendet werden.

Dateien importieren

Das obige Beispiel enthält zwar keine Importanweisung, Solidity unterstützt jedoch Importanweisungen, die den in JavaScript verfügbaren Anweisungen sehr ähnlich sind.

Die folgende Anweisung importiert alle globalen Symbole aus "Dateiname".

import "filename";

Im folgenden Beispiel wird ein neues globales Symbol symbolName erstellt, dessen Mitglieder alle globalen Symbole aus "Dateiname" sind.

import * as symbolName from "filename";

Verwenden Sie den Import "./x" als x;, um eine Datei x aus demselben Verzeichnis wie die aktuelle Datei zu importieren. Wenn Sie "x" als x importieren; Stattdessen könnte auf eine andere Datei in einem globalen "Include-Verzeichnis" verwiesen werden.

Reservierte Schlüsselwörter

Im Folgenden sind die reservierten Schlüsselwörter in Solidity aufgeführt -

abstrakt nach alias anwenden
Auto Fall Fang Kopie von
Standard definieren Finale unveränderlich
Geräte im in der Reihe Lassen
Makro Spiel veränderlich Null
von überschreiben teilweise versprechen
Referenz umsetzbar versiegelt Größe von
statisch unterstützt Schalter Versuchen
typedef eine Art von deaktiviert

Wir verwenden Remix IDE, um unsere Solidity Code-Basis zu kompilieren und auszuführen.

Step 1 - Kopieren Sie den angegebenen Code im Abschnitt Remix IDE Code.

Beispiel

pragma solidity ^0.5.0;
contract SolidityTest {
   constructor() public{
   }
   function getResult() public view returns(uint){
      uint a = 1;
      uint b = 2;
      uint result = a + b;
      return result;
   }
}

Step 2 - Klicken Sie auf der Registerkarte Kompilieren auf Start to Compile Taste.

Step 3 - Klicken Sie unter Registerkarte Ausführen auf Deploy Taste.

Step 4 - Wählen Sie auf der Registerkarte Ausführen die Option Aus SolidityTest at 0x... in Dropdown.

Step 5 - Klicken Sie auf getResult Schaltfläche zum Anzeigen des Ergebnisses.

Ausgabe

0: uint256: 3

Solidity unterstützt sowohl C-Style- als auch C ++ - Style-Kommentare.

  • Jeder Text zwischen einem // und dem Ende einer Zeile wird als Kommentar behandelt und vom Solidity Compiler ignoriert.

  • Jeder Text zwischen den Zeichen / * und * / wird als Kommentar behandelt. Dies kann mehrere Zeilen umfassen.

Beispiel

Das folgende Beispiel zeigt, wie Kommentare in Solidity verwendet werden.

function getResult() public view returns(uint){
   // This is a comment. It is similar to comments in C++

   /*
      * This is a multi-line comment in solidity
      * It is very similar to comments in C Programming
   */
   uint a = 1;
   uint b = 2;
   uint result = a + b;
   return result;
}

Während Sie ein Programm in einer beliebigen Sprache schreiben, müssen Sie verschiedene Variablen verwenden, um verschiedene Informationen zu speichern. Variablen sind nichts anderes als reservierte Speicherplätze zum Speichern von Werten. Dies bedeutet, dass Sie beim Erstellen einer Variablen Speicherplatz im Speicher reservieren.

Möglicherweise möchten Sie Informationen verschiedener Datentypen wie Zeichen, Breitzeichen, Ganzzahlen, Gleitkomma, Doppel-Gleitkomma, Boolesche Werte usw. speichern. Basierend auf dem Datentyp einer Variablen weist das Betriebssystem Speicher zu und entscheidet, was in der gespeichert werden kann reservierter Speicher.

Werttypen

Solidity bietet dem Programmierer eine große Auswahl an integrierten und benutzerdefinierten Datentypen. In der folgenden Tabelle sind sieben grundlegende C ++ - Datentypen aufgeführt:

Art Stichwort Werte
Boolescher Wert Bool wahr falsch
Ganze Zahl int / uint Vorzeichenbehaftete und vorzeichenlose Ganzzahlen unterschiedlicher Größe.
Ganze Zahl int8 bis int256 Int von 8 Bit bis 256 Bit signiert. int256 ist dasselbe wie int.
Ganze Zahl uint8 bis uint256 Int ohne Vorzeichen von 8 Bit bis 256 Bit. uint256 ist dasselbe wie uint.
Festkommazahlen fest / nicht fixiert Vorzeichenbehaftete und vorzeichenlose Festkommazahlen unterschiedlicher Größe.
Festkommazahlen fest / nicht fixiert Vorzeichenbehaftete und vorzeichenlose Festkommazahlen unterschiedlicher Größe.
Festkommazahlen fixedMxN Vorzeichenbehaftete Festkommazahl, wobei M die Anzahl der vom Typ genommenen Bits und N die Dezimalstellen darstellt. M sollte durch 8 teilbar sein und geht von 8 bis 256. N kann von 0 bis 80 sein. Fest ist dasselbe wie fest 128 x 18.
Festkommazahlen ufixedMxN Festpunktnummer ohne Vorzeichen, wobei M die Anzahl der vom Typ genommenen Bits und N die Dezimalstellen darstellt. M sollte durch 8 teilbar sein und geht von 8 bis 256. N kann von 0 bis 80 sein. Ufixed ist dasselbe wie ufixed128x18.

Adresse

Adresse enthält den 20-Byte-Wert, der die Größe einer Ethereum-Adresse darstellt. Eine Adresse kann verwendet werden, um den Kontostand mithilfe der .balance-Methode abzurufen, und kann verwendet werden, um den Kontostand mithilfe der .transfer-Methode an eine andere Adresse zu übertragen.

address x = 0x212;
address myAddress = this;
if (x.balance < 10 && myAddress.balance >= 10) x.transfer(10);

Solidity unterstützt drei Arten von Variablen.

  • State Variables - Variablen, deren Werte dauerhaft in einem Vertragsspeicher gespeichert sind.

  • Local Variables - Variablen, deren Werte vorhanden sind, bis die Funktion ausgeführt wird.

  • Global Variables - Im globalen Namespace sind spezielle Variablen vorhanden, mit denen Informationen zur Blockchain abgerufen werden.

Solidity ist eine statisch typisierte Sprache. Dies bedeutet, dass der Status oder der lokale Variablentyp während der Deklaration angegeben werden muss. Jede deklarierte Variable hat immer einen Standardwert, der auf ihrem Typ basiert. Es gibt kein Konzept von "undefiniert" oder "null".

Zustandsvariable

Variablen, deren Werte dauerhaft in einem Vertragsspeicher gespeichert sind.

pragma solidity ^0.5.0;
contract SolidityTest {
   uint storedData;      // State variable
   constructor() public {
      storedData = 10;   // Using State variable
   }
}

Lokale Variable

Variablen, deren Werte nur innerhalb einer Funktion verfügbar sind, in der sie definiert sind. Funktionsparameter sind für diese Funktion immer lokal.

pragma solidity ^0.5.0;
contract SolidityTest {
   uint storedData; // State variable
   constructor() public {
      storedData = 10;   
   }
   function getResult() public view returns(uint){
      uint a = 1; // local variable
      uint b = 2;
      uint result = a + b;
      return result; //access the local variable
   }
}

Beispiel

pragma solidity ^0.5.0;
contract SolidityTest {
   uint storedData; // State variable
   constructor() public {
      storedData = 10;   
   }
   function getResult() public view returns(uint){
      uint a = 1; // local variable
      uint b = 2;
      uint result = a + b;
      return storedData; //access the state variable
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Ausgabe

0: uint256: 10

Globale Variablen

Hierbei handelt es sich um spezielle Variablen, die im globalen Arbeitsbereich vorhanden sind und Informationen zu den Blockchain- und Transaktionseigenschaften enthalten.

Name Kehrt zurück
blockhash (uint blockNumber) gibt (bytes32) zurück Hash des angegebenen Blocks - funktioniert nur für 256 neueste, ausgenommen aktuelle Blöcke
block.coinbase (Adresse zahlbar) Aktuelle Block Miner-Adresse
block.difficulty (uint) Aktuelle Blockschwierigkeit
block.gaslimit (uint) Aktuelle Blockgasbegrenzung
block.number (uint) Aktuelle Blocknummer
block.timestamp (uint) Aktueller Blockzeitstempel als Sekunden seit der Unix-Epoche
gasleft () gibt zurück (uint256) Restgas
msg.data (Bytes calldata) Komplette Anrufdaten
msg.sender (Adresse zahlbar) Absender der Nachricht (aktueller Anrufer)
msg.sig (bytes4) Die ersten vier Bytes der Aufrufdaten (Funktionskennung)
msg.value (uint) Anzahl der mit der Nachricht gesendeten Wei
jetzt (uint) Aktueller Blockzeitstempel
tx.gasprice (uint) Gaspreis der Transaktion
tx.origin (Adresse zahlbar) Absender der Transaktion

Namen von Solidity-Variablen

Beachten Sie beim Benennen Ihrer Variablen in Solidity die folgenden Regeln.

  • Sie sollten keines der reservierten Solidity-Schlüsselwörter als Variablennamen verwenden. Diese Schlüsselwörter werden im nächsten Abschnitt erwähnt. Beispielsweise sind break- oder boolesche Variablennamen ungültig.

  • Namen von Soliditätsvariablen sollten nicht mit einer Ziffer (0-9) beginnen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen. Beispielsweise ist 123test ein ungültiger Variablenname, _123test jedoch ein gültiger.

  • Bei Namen von Soliditätsvariablen wird zwischen Groß- und Kleinschreibung unterschieden. Zum Beispiel sind Name und Name zwei verschiedene Variablen.

Der Bereich lokaler Variablen ist auf die Funktion beschränkt, in der sie definiert sind. Statusvariablen können jedoch drei Arten von Bereichen haben.

  • Public- Auf Variablen des öffentlichen Zustands kann sowohl intern als auch über Nachrichten zugegriffen werden. Für eine öffentliche Zustandsvariable wird eine automatische Getterfunktion generiert.

  • Internal - Auf interne Statusvariablen kann nur intern aus dem aktuellen Vertrag oder einem daraus abgeleiteten Vertrag zugegriffen werden, ohne diesen zu verwenden.

  • Private - Auf private Statusvariablen kann nur intern aus dem aktuellen Vertrag zugegriffen werden, sie sind nicht in dem daraus abgeleiteten Vertrag definiert.

Beispiel

pragma solidity ^0.5.0;
contract C {
   uint public data = 30;
   uint internal iData= 10;
   
   function x() public returns (uint) {
      data = 3; // internal access
      return data;
   }
}
contract Caller {
   C c = new C();
   function f() public view returns (uint) {
      return c.data(); //external access
   }
}
contract D is C {
   function y() public returns (uint) {
      iData = 3; // internal access
      return iData;
   }
   function getResult() public view returns(uint){
      uint a = 1; // local variable
      uint b = 2;
      uint result = a + b;
      return storedData; //access the state variable
   }
}

Was ist ein Operator?

Nehmen wir einen einfachen Ausdruck 4 + 5 is equal to 9. Hier heißen 4 und 5operands und '+' heißt das operator. Solidity unterstützt die folgenden Operatortypen.

  • Rechenzeichen
  • Vergleichsoperatoren
  • Logische (oder relationale) Operatoren
  • Zuweisungsoperatoren
  • Bedingte (oder ternäre) Operatoren

Schauen wir uns alle Operatoren einzeln an.

Rechenzeichen

Solidity unterstützt die folgenden arithmetischen Operatoren:

Angenommen, Variable A hält 10 und Variable B hält 20, dann -

Beispiel zeigen

Sr.Nr. Betreiber & Beschreibung
1

+ (Addition)

Fügt zwei Operanden hinzu

Ex: A + B ergibt 30

2

- (Subtraction)

Subtrahiert den zweiten Operanden vom ersten

Ex: A - B ergibt -10

3

* (Multiplication)

Multiplizieren Sie beide Operanden

Ex: A * B ergibt 200

4

/ (Division)

Teilen Sie den Zähler durch den Nenner

Ex: B / A ergibt 2

5

% (Modulus)

Gibt den Rest einer Ganzzahldivision aus

Ex: B% A ergibt 0

6

++ (Increment)

Erhöht einen ganzzahligen Wert um eins

Ex: A ++ gibt 11

7

-- (Decrement)

Verringert einen ganzzahligen Wert um eins

Ex: A-- wird 9 geben

Vergleichsoperatoren

Solidity unterstützt die folgenden Vergleichsoperatoren:

Angenommen, Variable A hält 10 und Variable B hält 20, dann -

Beispiel zeigen

Sr.Nr. Betreiber & Beschreibung
1

= = (Equal)

Überprüft, ob der Wert von zwei Operanden gleich ist oder nicht. Wenn ja, wird die Bedingung erfüllt.

Ex: (A == B) ist nicht wahr.

2

!= (Not Equal)

Überprüft, ob der Wert von zwei Operanden gleich ist oder nicht. Wenn die Werte nicht gleich sind, wird die Bedingung wahr.

Ex: (A! = B) ist wahr.

3

> (Greater than)

Überprüft, ob der Wert des linken Operanden größer als der Wert des rechten Operanden ist. Wenn ja, wird die Bedingung erfüllt.

Ex: (A> B) ist nicht wahr.

4

< (Less than)

Überprüft, ob der Wert des linken Operanden kleiner als der Wert des rechten Operanden ist. Wenn ja, wird die Bedingung erfüllt.

Ex: (A <B) ist wahr.

5

>= (Greater than or Equal to)

Überprüft, ob der Wert des linken Operanden größer oder gleich dem Wert des rechten Operanden ist. Wenn ja, wird die Bedingung erfüllt.

Ex: (A> = B) ist nicht wahr.

6

<= (Less than or Equal to)

Überprüft, ob der Wert des linken Operanden kleiner oder gleich dem Wert des rechten Operanden ist. Wenn ja, wird die Bedingung erfüllt.

Ex: (A <= B) ist wahr.

Logische Operatoren

Solidity unterstützt die folgenden logischen Operatoren:

Angenommen, Variable A hält 10 und Variable B hält 20, dann -

Beispiel zeigen

Sr.Nr. Betreiber & Beschreibung
1

&& (Logical AND)

Wenn beide Operanden ungleich Null sind, wird die Bedingung wahr.

Ex: (A && B) ist wahr.

2

|| (Logical OR)

Wenn einer der beiden Operanden ungleich Null ist, wird die Bedingung erfüllt.

Ex: (A || B) ist wahr.

3

! (Logical NOT)

Kehrt den logischen Zustand seines Operanden um. Wenn eine Bedingung wahr ist, macht der Operator Logical NOT sie falsch.

Ex:! (A && B) ist falsch.

Bitweise Operatoren

Solidity unterstützt die folgenden bitweisen Operatoren:

Angenommen, Variable A hält 2 und Variable B hält 3, dann -

Beispiel zeigen

Sr.Nr. Betreiber & Beschreibung
1

& (Bitwise AND)

Es führt eine boolesche UND-Operation für jedes Bit seiner ganzzahligen Argumente aus.

Ex: (A & B) ist 2.

2

| (BitWise OR)

Es führt eine boolesche ODER-Operation für jedes Bit seiner ganzzahligen Argumente aus.

Ex: (A | B) ist 3.

3

^ (Bitwise XOR)

Es führt eine boolesche exklusive ODER-Operation für jedes Bit seiner ganzzahligen Argumente aus. Exklusives ODER bedeutet, dass entweder Operand eins wahr ist oder Operand zwei wahr ist, aber nicht beide.

Ex: (A ^ B) ist 1.

4

~ (Bitwise Not)

Es ist ein unärer Operator und arbeitet durch Umkehren aller Bits im Operanden.

Ex: (~ B) ist -4.

5

<< (Left Shift)

Es verschiebt alle Bits in seinem ersten Operanden um die im zweiten Operanden angegebene Anzahl von Stellen nach links. Neue Bits werden mit Nullen gefüllt. Das Verschieben eines Werts um eine Position entspricht dem Multiplizieren mit 2, das Verschieben von zwei Positionen entspricht dem Multiplizieren mit 4 usw.

Ex: (A << 1) ist 4.

6

>> (Right Shift)

Binärer Rechtsschieber. Der Wert des linken Operanden wird um die vom rechten Operanden angegebene Anzahl von Bits nach rechts verschoben.

Ex: (A >> 1) ist 1.

7

>>> (Right shift with Zero)

Dieser Operator ist genau wie der Operator >>, außer dass die links verschobenen Bits immer Null sind.

Ex: (A >>> 1) ist 1.

Zuweisungsoperatoren

Solidity unterstützt die folgenden Zuweisungsoperatoren:

Beispiel zeigen

Sr.Nr. Betreiber & Beschreibung
1

= (Simple Assignment )

Weist dem linken Operanden Werte vom rechten Operanden zu

Ex: C = A + B weist C den Wert von A + B zu

2

+= (Add and Assignment)

Es fügt dem linken Operanden den rechten Operanden hinzu und weist das Ergebnis dem linken Operanden zu.

Ex: C + = A entspricht C = C + A.

3

−= (Subtract and Assignment)

Es subtrahiert den rechten Operanden vom linken Operanden und weist das Ergebnis dem linken Operanden zu.

Ex: C - = A entspricht C = C - A.

4

*= (Multiply and Assignment)

Es multipliziert den rechten Operanden mit dem linken Operanden und weist das Ergebnis dem linken Operanden zu.

Ex: C * = A entspricht C = C * A.

5

/= (Divide and Assignment)

Es teilt den linken Operanden mit dem rechten Operanden und weist das Ergebnis dem linken Operanden zu.

Ex: C / = A entspricht C = C / A.

6

%= (Modules and Assignment)

Es nimmt den Modul mit zwei Operanden und weist das Ergebnis dem linken Operanden zu.

Ex: C% = A entspricht C = C% A.

Note - Dieselbe Logik gilt für bitweise Operatoren, sodass sie wie << =, >> =, >> =, & =, | = und ^ = aussehen.

Bedingter Operator (? :)

Der bedingte Operator wertet zuerst einen Ausdruck für einen wahren oder falschen Wert aus und führt dann abhängig vom Ergebnis der Auswertung eine der beiden angegebenen Anweisungen aus.

Beispiel zeigen

Sr.Nr. Betreiber und Beschreibung
1

? : (Conditional )

Wenn Bedingung wahr ist? Dann Wert X: Andernfalls Wert Y.

Beim Schreiben eines Vertrags kann es vorkommen, dass Sie eine Aktion immer wieder ausführen müssen. In solchen Situationen müssten Sie Schleifenanweisungen schreiben, um die Anzahl der Zeilen zu verringern.

Solidity unterstützt alle notwendigen Schleifen, um den Programmierdruck zu verringern.

Sr.Nr. Schleifen & Beschreibung
1

While-Schleife

Die grundlegendste Schleife in Solidity ist die while-Schleife, die in diesem Kapitel behandelt wird.

2

mach ... während Loop

Die do ... while-Schleife ähnelt der while-Schleife, außer dass die Bedingungsprüfung am Ende der Schleife erfolgt.

3

Für Schleife

Die for-Schleife ist die kompakteste Form der Schleife. Es enthält die folgenden drei wichtigen Teile.

4

Schleifensteuerung

Solidity bietet die volle Kontrolle über die Verarbeitung von Schleifen und switch-Anweisungen.

Beim Schreiben eines Programms kann es vorkommen, dass Sie einen aus einem bestimmten Satz von Pfaden übernehmen müssen. In solchen Fällen müssen Sie bedingte Anweisungen verwenden, mit denen Ihr Programm korrekte Entscheidungen treffen und die richtigen Aktionen ausführen kann.

Solidity unterstützt bedingte Anweisungen, mit denen unterschiedliche Aktionen basierend auf unterschiedlichen Bedingungen ausgeführt werden. Hier erklären wir dasif..else Erklärung.

Flussdiagramm von if-else

Das folgende Flussdiagramm zeigt, wie die if-else-Anweisung funktioniert.

Die Festigkeit unterstützt die folgenden Formen von if..else Aussage -

Sr.Nr. Aussagen & Beschreibung
1

if-Anweisung

Die if-Anweisung ist die grundlegende Steueranweisung, mit der Solidity Entscheidungen treffen und Anweisungen unter bestimmten Bedingungen ausführen kann.

2

if ... else-Anweisung

Die Anweisung 'if ... else' ist die nächste Form der Steueranweisung, mit der Solidity Anweisungen kontrollierter ausführen kann.

3

if ... else if ... Anweisung.

Die if ... else if ... -Anweisung ist eine erweiterte Form von if ... else, die es Solidity ermöglicht, aus mehreren Bedingungen eine korrekte Entscheidung zu treffen.

Solidity unterstützt das String-Literal sowohl in doppelten Anführungszeichen (") als auch in einfachen Anführungszeichen ('). Es stellt String als Datentyp bereit, um eine Variable vom Typ String zu deklarieren.

pragma solidity ^0.5.0;

contract SolidityTest {
   string data = "test";
}

Im obigen Beispiel ist "test" ein Zeichenfolgenliteral und data eine Zeichenfolgenvariable. Ein bevorzugterer Weg ist die Verwendung von Bytetypen anstelle von String, da die String-Operation im Vergleich zur Byte-Operation mehr Gas erfordert. Solidity bietet eine integrierte Konvertierung zwischen Bytes in Zeichenfolgen und umgekehrt. In Solidity können wir einer Variablen vom Typ byte32 auf einfache Weise ein String-Literal zuweisen. Solidity betrachtet es als ein Byte32-Literal.

pragma solidity ^0.5.0;

contract SolidityTest {
   bytes32 data = "test";
}

Escape-Charaktere

Sr.Nr. Charakterbeschreibung
1

\n

Startet eine neue Zeile.

2

\\

Backslash

3

\'

Einfaches Zitat

4

\"

Doppeltes Zitat

5

\b

Rücktaste

6

\f

Formularvorschub

7

\r

Wagenrücklauf

8

\t

Tab

9

\v

Vertikale Registerkarte

10

\xNN

Stellt den Hex-Wert dar und fügt die entsprechenden Bytes ein.

11

\uNNNN

Repräsentiert den Unicode-Wert und fügt die UTF-8-Sequenz ein.

Konvertierung von Bytes in Zeichenfolgen

Bytes können mit dem Konstruktor string () in String konvertiert werden.

bytes memory bstr = new bytes(10);
string message = string(bstr);

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie die Zeichenfolge in Solidity funktioniert.

pragma solidity ^0.5.0;

contract SolidityTest {   
   constructor() public{       
   }
   function getResult() public view returns(string memory){
      uint a = 1; 
      uint b = 2;
      uint result = a + b;
      return integerToString(result); 
   }
   function integerToString(uint _i) internal pure 
      returns (string memory) {
      
      if (_i == 0) {
         return "0";
      }
      uint j = _i;
      uint len;
      
      while (j != 0) {
         len++;
         j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;
      
      while (_i != 0) {
         bstr[k--] = byte(uint8(48 + _i % 10));
         _i /= 10;
      }
      return string(bstr);
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Ausgabe

0: string: 3

Array ist eine Datenstruktur, in der eine sequentielle Sammlung von Elementen desselben Typs mit fester Größe gespeichert wird. Ein Array wird zum Speichern einer Sammlung von Daten verwendet. Oft ist es jedoch sinnvoller, sich ein Array als eine Sammlung von Variablen desselben Typs vorzustellen.

Anstatt einzelne Variablen wie Nummer 0, Nummer 1, ... und Nummer 99 zu deklarieren, deklarieren Sie eine Array-Variable wie Zahlen und verwenden Zahlen [0], Zahlen [1] und ..., Zahlen [99] zur Darstellung einzelne Variablen. Auf ein bestimmtes Element in einem Array wird über einen Index zugegriffen.

In Solidity kann ein Array eine feste Größe zur Kompilierungszeit oder eine dynamische Größe haben. Für Speicherarrays können auch verschiedene Arten von Elementen vorhanden sein. Im Falle eines Speicherarrays kann der Elementtyp nicht zugeordnet werden. Wenn er als Funktionsparameter verwendet werden soll, sollte der Elementtyp ein ABI-Typ sein.

Alle Arrays bestehen aus zusammenhängenden Speicherstellen. Die niedrigste Adresse entspricht dem ersten Element und die höchste Adresse dem letzten Element.

Arrays deklarieren

Um ein Array mit fester Größe in Solidity zu deklarieren, gibt der Programmierer den Typ der Elemente und die Anzahl der für ein Array erforderlichen Elemente wie folgt an:

type arrayName [ arraySize ];

Dies wird als eindimensionales Array bezeichnet. DasarraySize muss eine ganzzahlige Konstante größer als Null sein und typekann ein beliebiger gültiger Solidity-Datentyp sein. Verwenden Sie diese Anweisung, um beispielsweise ein Array mit 10 Elementen zu deklarieren, das als Balance vom Typ uint bezeichnet wird.

uint balance[10];

Um ein Array mit dynamischer Größe in Solidity zu deklarieren, gibt der Programmierer den Typ der Elemente wie folgt an:

type[] arrayName;

Arrays initialisieren

Sie können Solidity-Array-Elemente entweder einzeln oder mithilfe einer einzelnen Anweisung wie folgt initialisieren:

uint balance[3] = [1, 2, 3];

Die Anzahl der Werte zwischen geschweiften Klammern [] darf nicht größer sein als die Anzahl der Elemente, die wir für das Array zwischen eckigen Klammern [] deklarieren. Es folgt ein Beispiel zum Zuweisen eines einzelnen Elements des Arrays:

Wenn Sie die Größe des Arrays weglassen, wird ein Array erstellt, das gerade groß genug ist, um die Initialisierung aufzunehmen. Deshalb, wenn Sie schreiben -

uint balance[] = [1, 2, 3];

Sie erstellen genau das gleiche Array wie im vorherigen Beispiel.

balance[2] = 5;

Die obige Anweisung weist Elementnummer 3 rd in der Anordnung ein Wert von 5.

Erstellen dynamischer Speicherarrays

Dynamische Speicherarrays werden mit einem neuen Schlüsselwort erstellt.

uint size = 3;
uint balance[] = new uint[](size);

Zugriff auf Array-Elemente

Auf ein Element wird zugegriffen, indem der Arrayname indiziert wird. Dazu wird der Index des Elements in eckige Klammern nach dem Namen des Arrays gesetzt. Zum Beispiel -

uint salary = balance[2];

Die obige Anweisung nimmt das dritte Element aus dem Array und weist den Wert der Gehaltsvariablen zu. Es folgt ein Beispiel, in dem alle oben genannten drei Konzepte verwendet werden. Deklaration, Zuweisung und Zugriff auf Arrays -

Mitglieder

  • length- length gibt die Größe des Arrays zurück. Länge kann verwendet werden, um die Größe des dynamischen Arrays zu ändern, um es einzustellen.

  • push- push ermöglicht das Anhängen eines Elements an ein dynamisches Speicherarray am Ende. Es gibt die neue Länge des Arrays zurück.

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie die Arrays in Solidity funktionieren.

pragma solidity ^0.5.0;

contract test {
   function testArray() public pure{
      uint len = 7; 
      
      //dynamic array
      uint[] memory a = new uint[](7);
      
      //bytes is same as byte[]
      bytes memory b = new bytes(len);
      
      assert(a.length == 7);
      assert(b.length == len);
      
      //access array variable
      a[6] = 8;
      
      //test array variable
      assert(a[6] == 8);
      
      //static array
      uint[3] memory c = [uint(1) , 2, 3];
      assert(c.length == 3);
   }
}

Aufzählungen beschränken eine Variable auf einen von nur wenigen vordefinierten Werten. Die Werte in dieser Aufzählungsliste werden als Aufzählungen bezeichnet.

Durch die Verwendung von Aufzählungen ist es möglich, die Anzahl der Fehler in Ihrem Code zu reduzieren.

Wenn wir beispielsweise eine Anwendung für einen Frischsaftladen in Betracht ziehen, wäre es möglich, die Glasgröße auf klein, mittel und groß zu beschränken. Dies würde sicherstellen, dass niemand eine andere Größe als klein, mittel oder groß bestellen kann.

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie die Aufzählung in Solidity funktioniert.

pragma solidity ^0.5.0;

contract test {
   enum FreshJuiceSize{ SMALL, MEDIUM, LARGE }
   FreshJuiceSize choice;
   FreshJuiceSize constant defaultChoice = FreshJuiceSize.MEDIUM;

   function setLarge() public {
      choice = FreshJuiceSize.LARGE;
   }
   function getChoice() public view returns (FreshJuiceSize) {
      return choice;
   }
   function getDefaultChoice() public pure returns (uint) {
      return uint(defaultChoice);
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Erster Klick setLarge Klicken Sie auf die Schaltfläche, um den Wert auf GROSS festzulegen, und klicken Sie dann auf getChoice um die ausgewählte Auswahl zu erhalten.

Ausgabe

uint8: 2

Klicken getDefaultChoice Schaltfläche, um die Standardauswahl zu erhalten.

Ausgabe

uint256: 1

Strukturtypen werden verwendet, um einen Datensatz darzustellen. Angenommen, Sie möchten Ihre Bücher in einer Bibliothek verfolgen. Möglicherweise möchten Sie die folgenden Attribute für jedes Buch verfolgen:

  • Title
  • Author
  • Subject
  • Buch-ID

Struktur definieren

Um eine Struktur zu definieren, müssen Sie die verwenden structStichwort. Das Schlüsselwort struct definiert einen neuen Datentyp mit mehr als einem Mitglied. Das Format der struct-Anweisung lautet wie folgt:

struct struct_name { 
   type1 type_name_1;
   type2 type_name_2;
   type3 type_name_3;
}

Beispiel

struct Book { 
   string title;
   string author;
   uint book_id;
}

Zugriff auf eine Struktur und ihre Variable

Um auf ein Mitglied einer Struktur zuzugreifen, verwenden wir den Elementzugriffsoperator (.). Der Elementzugriffsoperator wird als Punkt zwischen dem Namen der Strukturvariablen und dem Strukturelement codiert, auf das wir zugreifen möchten. Sie würden die Struktur verwenden, um Variablen vom Strukturtyp zu definieren. Das folgende Beispiel zeigt, wie eine Struktur in einem Programm verwendet wird.

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie die Strukturen in Solidity funktionieren.

pragma solidity ^0.5.0;

contract test {
   struct Book { 
      string title;
      string author;
      uint book_id;
   }
   Book book;

   function setBook() public {
      book = Book('Learn Java', 'TP', 1);
   }
   function getBookId() public view returns (uint) {
      return book.book_id;
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Erster Klick setBook Klicken Sie auf die Schaltfläche, um den Wert auf GROSS festzulegen, und klicken Sie dann auf getBookId um die ausgewählte Buch-ID zu erhalten.

Ausgabe

uint256: 1

Die Zuordnung ist ein Referenztyp für Arrays und Strukturen. Es folgt die Syntax zum Deklarieren eines Zuordnungstyps.

mapping(_KeyType => _ValueType)

Wo

  • _KeyType- kann ein beliebiger integrierter Typ plus Bytes und Zeichenfolge sein. Es sind keine Referenztypen oder komplexen Objekte zulässig.

  • _ValueType - kann jeder Typ sein.

Überlegungen

  • Mapping kann nur den Typ haben storage und werden im Allgemeinen für Zustandsvariablen verwendet.

  • Die Zuordnung kann als öffentlich markiert werden. Solidität schafft automatisch Getter dafür.

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie der Zuordnungstyp in Solidity funktioniert.

pragma solidity ^0.5.0;

contract LedgerBalance {
   mapping(address => uint) public balances;

   function updateBalance(uint newBalance) public {
      balances[msg.sender] = newBalance;
   }
}
contract Updater {
   function updateBalance() public returns (uint) {
      LedgerBalance ledgerBalance = new LedgerBalance();
      ledgerBalance.updateBalance(10);
      return ledgerBalance.balances(address(this));
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Erster Klick updateBalance Klicken Sie auf die Schaltfläche, um den Wert auf 10 festzulegen, und schauen Sie dann in die Protokolle, in denen die dekodierte Ausgabe als - angezeigt wird.

Ausgabe

{
   "0": "uint256: 10"
}

Solidity ermöglicht sowohl implizite als auch explizite Konvertierung. Der Solidity-Compiler ermöglicht die implizite Konvertierung zwischen zwei Datentypen, sofern keine implizite Konvertierung möglich ist und keine Informationen verloren gehen. Zum Beispiel ist uint8 in uint16 konvertierbar, aber int8 ist in uint256 konvertierbar, da int8 einen negativen Wert enthalten kann, der in uint256 nicht zulässig ist.

Explizite Konvertierung

Wir können einen Datentyp mithilfe der Konstruktorsyntax explizit in einen anderen konvertieren.

int8 y = -3;
uint x = uint(y);
//Now x = 0xfffff..fd == two complement representation of -3 in 256 bit format.

Die Konvertierung in einen kleineren Typ kostet Bits höherer Ordnung.

uint32 a = 0x12345678;
uint16 b = uint16(a); // b = 0x5678

Bei der Konvertierung in einen höheren Typ werden links Füllbits hinzugefügt.

uint16 a = 0x1234;
uint32 b = uint32(a); // b = 0x00001234

Die Konvertierung in kleinere Bytes kostet Daten höherer Ordnung.

bytes2 a = 0x1234;
bytes1 b = bytes1(a); // b = 0x12

Bei der Konvertierung in ein größeres Byte werden rechts Füllbits hinzugefügt.

bytes2 a = 0x1234;
bytes4 b = bytes4(a); // b = 0x12340000

Die Konvertierung zwischen Bytes fester Größe und int ist nur möglich, wenn beide dieselbe Größe haben.

bytes2 a = 0x1234;
uint32 b = uint16(a); // b = 0x00001234
uint32 c = uint32(bytes4(a)); // c = 0x12340000
uint8 d = uint8(uint16(a)); // d = 0x34
uint8 e = uint8(bytes1(a)); // e = 0x12

Hexadezimalzahlen können jedem Ganzzahltyp zugewiesen werden, wenn keine Kürzung erforderlich ist.

uint8 a = 12; // no error
uint32 b = 1234; // no error
uint16 c = 0x123456; // error, as truncation required to 0x3456

In der Solidität können wir Wei, Finney, Szabo oder Ether als Suffix für ein Literal verwenden, um verschiedene ätherbasierte Bezeichnungen umzuwandeln. Die niedrigste Einheit ist wei und 1e12 steht für 1 x 10 12 .

assert(1 wei == 1);
assert(1 szabo == 1e12);
assert(1 finney == 1e15);
assert(1 ether == 1e18);
assert(2 ether == 2000 fenny);

Zeiteinheiten

Ähnlich wie bei der Währung hat Solidity Zeiteinheiten, bei denen die niedrigste Einheit die Sekunde ist, und wir können Sekunden, Minuten, Stunden, Tage und Wochen als Suffix verwenden, um die Zeit zu bezeichnen.

assert(1 seconds == 1);
assert(1 minutes == 60 seconds);
assert(1 hours == 60 minutes);
assert(1 day == 24 hours);
assert(1 week == 7 days);

Spezielle Variablen sind global verfügbare Variablen und enthalten Informationen zur Blockchain. Es folgt die Liste der speziellen Variablen -

Sr.Nr. Spezielle Variable & Beschreibung
1

blockhash(uint blockNumber) returns (bytes32)

Hash des angegebenen Blocks - funktioniert nur für 256 neueste, ausgenommen aktuelle Blöcke.

2

block.coinbase (address payable)

Aktuelle Block Miner-Adresse.

3

block.difficulty (uint)

aktuelle Blockschwierigkeit.

4

block.gaslimit (uint)

Aktuelle Blockgasbegrenzung.

5

block.number (uint)

Aktuelle Blocknummer.

6

block.timestamp

Aktueller Blockzeitstempel als Sekunden seit der Unix-Epoche.

7

gasleft() returns (uint256)

Restgas.

8

msg.data (bytes calldata)

Komplette Anrufdaten.

9

msg.sender (address payable)

Absender der Nachricht (aktueller Anruf).

10

msg.sig (bytes4)

Die ersten vier Bytes der Aufrufdaten (dh Funktionskennung)

11

msg.value (uint)

Anzahl der mit der Nachricht gesendeten Wei.

12

now (uint)

Aktueller Blockzeitstempel (Alias ​​für block.timestamp).

13

tx.gasprice (uint)

Gaspreis der Transaktion.

14

tx.origin (address payable)

Absender der Transaktion (vollständige Anrufkette).

Beispiel

Versuchen Sie den folgenden Code, um die Verwendung von msg zu sehen, einer speziellen Variablen, um die Absenderadresse in Solidity abzurufen.

pragma solidity ^0.5.0;

contract LedgerBalance {
   mapping(address => uint) public balances;

   function updateBalance(uint newBalance) public {
      balances[msg.sender] = newBalance;
   }
}
contract Updater {
   function updateBalance() public returns (uint) {
      LedgerBalance ledgerBalance = new LedgerBalance();
      ledgerBalance.updateBalance(10);
      return ledgerBalance.balances(address(this));
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Erster Klick updateBalance Klicken Sie auf die Schaltfläche, um den Wert auf 10 festzulegen, und schauen Sie dann in die Protokolle, in denen die dekodierte Ausgabe als - angezeigt wird.

Ausgabe

{
   "0": "uint256: 10"
}

Style Guide hilft dabei, das Codelayout konsistent zu halten und den Code besser lesbar zu machen. Im Folgenden finden Sie die besten Vorgehensweisen beim Schreiben von Verträgen mit Solidity.

Code-Layout

  • Indentation- Verwenden Sie 4 Leerzeichen anstelle der Registerkarte, um die Einrückungsstufe beizubehalten. Vermeiden Sie das Mischen von Leerzeichen mit Tabulatoren.

  • Two Blank Lines Rule - Verwenden Sie zwei Leerzeilen zwischen zwei Vertragsdefinitionen.

pragma solidity ^0.5.0;

contract LedgerBalance {
   //...
}
contract Updater {
   //...
}
  • One Blank Line Rule- Verwenden Sie 1 Leerzeile zwischen zwei Funktionen. Wenn nur eine Deklaration vorliegt, müssen keine Leerzeilen vorhanden sein.

pragma solidity ^0.5.0;

contract A {
   function balance() public pure;
   function account() public pure;
}
contract B is A {
   function balance() public pure {
      // ...
   }
   function account() public pure {
      // ...
   }
}
  • Maximum Line Length - Eine einzelne Zeile sollte nicht 79 Zeichen umfassen, damit die Leser den Code leicht analysieren können.

  • Wrapping rules- Das erste Argument steht in einer neuen Zeile, ohne die Klammer zu öffnen. Verwenden Sie einen einzelnen Einzug pro Argument. Abschlusselement); sollte der letzte sein.

function_with_a_long_name(
   longArgument1,
   longArgument2,
   longArgument3
);
variable = function_with_a_long_name(
   longArgument1,
   longArgument2,
   longArgument3
);
event multipleArguments(
   address sender,
   address recipient,
   uint256 publicKey,
   uint256 amount,
   bytes32[] options
);
MultipleArguments(
   sender,
   recipient,
   publicKey,
   amount,
   options
);
  • Source Code Encoding - UTF-8- oder ASCII-Codierung ist vorzugsweise zu verwenden.

  • Imports - Importanweisungen sollten direkt nach der Pragma-Deklaration am Anfang der Datei platziert werden.

  • Order of Functions - Funktionen sollten nach ihrer Sichtbarkeit gruppiert werden.

pragma solidity ^0.5.0;

contract A {
   constructor() public {
      // ...
   }
   function() external {
      // ...
   }

   // External functions
   // ...

   // External view functions
   // ...

   // External pure functions 
   // ...

   // Public functions
   // ...

   // Internal functions
   // ...

   // Private functions
   // ...
}
  • Avoid extra whitespaces - Vermeiden Sie Leerzeichen unmittelbar in Klammern, Klammern oder Klammern.

  • Control structures- Klammern sollten in derselben Zeile wie die Deklaration geöffnet werden. Schließen Sie auf ihrer eigenen Linie, wobei Sie die gleiche Einrückung beibehalten. Verwenden Sie ein Leerzeichen mit öffnender Klammer.

pragma solidity ^0.5.0;

contract Coin {
   struct Bank {
      address owner;
      uint balance;
   }
}
if (x < 3) {
   x += 1;
} else if (x > 7) {
   x -= 1;
} else {
   x = 5;
}
if (x < 3)
   x += 1;
else
   x -= 1;
  • Function Declaration- Verwenden Sie die obige Regel für Zahnspangen. Fügen Sie immer ein Sichtbarkeitsetikett hinzu. Das Sichtbarkeitsetikett sollte vor jedem benutzerdefinierten Modifikator an erster Stelle stehen.

function kill() public onlyowner {
   selfdestruct(owner);
}
  • Mappings - Vermeiden Sie Leerzeichen, wenn Sie Zuordnungsvariablen deklarieren.

mapping(uint => uint) map;
mapping(address => bool) registeredAddresses;
mapping(uint => mapping(bool => Data[])) public data;
mapping(uint => mapping(uint => s)) data;
  • Variable declaration - Vermeiden Sie Leerzeichen, während Sie Array-Variablen deklarieren.

uint[] x;  // not unit [] x;
  • String declaration - Verwenden Sie doppelte Anführungszeichen, um eine Zeichenfolge anstelle von einfachen Anführungszeichen zu deklarieren.

str = "foo";
str = "Hamlet says, 'To be or not to be...'";

Reihenfolge des Layouts

Die Elemente sollten in der folgenden Reihenfolge angeordnet sein.

  • Pragma Aussagen

  • Anweisungen importieren

  • Interfaces

  • Libraries

  • Contracts

Innerhalb von Schnittstellen, Bibliotheken oder Verträgen sollte die Reihenfolge wie folgt lauten:

  • Typdeklarationen

  • Zustandsvariablen

  • Events

  • Functions

Regeln der Namensgebung

  • Vertrag und Bibliothek sollten mit CapWords Style benannt werden. Zum Beispiel SmartContract, Eigentümer usw.

  • Vertrags- und Bibliotheksname sollten mit ihren Dateinamen übereinstimmen.

  • Verwenden Sie bei mehreren Verträgen / Bibliotheken in einer Datei den Namen des Kernvertrags / der Kernbibliothek.

Owned.sol

pragma solidity ^0.5.0;

// Owned.sol
contract Owned {
   address public owner;
   constructor() public {
      owner = msg.sender;
   }
   modifier onlyOwner {
      //....
   }
   function transferOwnership(address newOwner) public onlyOwner {
      //...
   }
}

Congress.sol

pragma solidity ^0.5.0;

// Congress.sol
import "./Owned.sol";

contract Congress is Owned, TokenRecipient {
   //...
}
  • Strukturnamen

    - Verwenden Sie CapWords Style wie SmartCoin.

  • Ereignisnamen

    - Verwenden Sie den CapWords-Stil wie Einzahlung, AfterTransfer.

  • Funktionsnamen

    - Verwenden Sie den MixedCase-Stil wie initiateSupply.

  • Lokale und staatliche Variablen

    - Verwenden Sie den MixedCase-Stil wie CreatorAddress, Supply.

  • Konstanten

    - Verwenden Sie alle Großbuchstaben mit Unterstrich, um Wörter wie MAX_BLOCKS zu trennen.

  • Modifikatornamen

    - Verwenden Sie mixCase Style wie onlyAfter.

  • Aufzählungsnamen

    - Verwenden Sie CapWords Style wie TokenGroup.

Eine Funktion ist eine Gruppe von wiederverwendbarem Code, der an einer beliebigen Stelle in Ihrem Programm aufgerufen werden kann. Dadurch entfällt die Notwendigkeit, immer wieder denselben Code zu schreiben. Es hilft Programmierern beim Schreiben modularer Codes. Mit Funktionen kann ein Programmierer ein großes Programm in eine Reihe kleiner und verwaltbarer Funktionen unterteilen.

Wie jede andere erweiterte Programmiersprache unterstützt auch Solidity alle Funktionen, die zum Schreiben von modularem Code mithilfe von Funktionen erforderlich sind. In diesem Abschnitt wird erläutert, wie Sie Ihre eigenen Funktionen in Solidity schreiben.

Funktionsdefinition

Bevor wir eine Funktion verwenden, müssen wir sie definieren. Die gebräuchlichste Methode zum Definieren einer Funktion in Solidity ist die Verwendung vonfunction Schlüsselwort, gefolgt von einem eindeutigen Funktionsnamen, einer Liste von Parametern (die möglicherweise leer sind) und einem Anweisungsblock, der von geschweiften Klammern umgeben ist.

Syntax

Die grundlegende Syntax wird hier gezeigt.

function function-name(parameter-list) scope returns() {
   //statements
}

Beispiel

Versuchen Sie das folgende Beispiel. Es definiert eine Funktion namens getResult, die keine Parameter akzeptiert -

pragma solidity ^0.5.0;

contract Test {
   function getResult() public view returns(uint){
      uint a = 1; // local variable
      uint b = 2;
      uint result = a + b;
      return result;
   }
}

Eine Funktion aufrufen

Um eine Funktion später im Vertrag aufzurufen, müssen Sie lediglich den Namen dieser Funktion wie im folgenden Code angegeben schreiben.

Versuchen Sie den folgenden Code, um zu verstehen, wie die Zeichenfolge in Solidity funktioniert.

pragma solidity ^0.5.0;

contract SolidityTest {   
   constructor() public{       
   }
   function getResult() public view returns(string memory){
      uint a = 1; 
      uint b = 2;
      uint result = a + b;
      return integerToString(result); 
   }
   function integerToString(uint _i) internal pure 
      returns (string memory) {
      
      if (_i == 0) {
         return "0";
      }
      uint j = _i;
      uint len;
      
      while (j != 0) {
         len++;
         j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;
      
      while (_i != 0) {
         bstr[k--] = byte(uint8(48 + _i % 10));
         _i /= 10;
      }
      return string(bstr);//access local variable
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Ausgabe

0: string: 3

Funktionsparameter

Bisher haben wir Funktionen ohne Parameter gesehen. Es gibt jedoch die Möglichkeit, beim Aufrufen einer Funktion verschiedene Parameter zu übergeben. Diese übergebenen Parameter können innerhalb der Funktion erfasst werden, und jede Manipulation kann über diese Parameter durchgeführt werden. Eine Funktion kann mehrere durch Komma getrennte Parameter annehmen.

Beispiel

Versuchen Sie das folgende Beispiel. Wir haben eine verwendetuint2strFunktion hier. Es braucht einen Parameter.

pragma solidity ^0.5.0;

contract SolidityTest {   
   constructor() public{       
   }
   function getResult() public view returns(string memory){
      uint a = 1; 
      uint b = 2;
      uint result = a + b;
      return integerToString(result); 
   }
   function integerToString(uint _i) internal pure 
      returns (string memory) {
      
      if (_i == 0) {
         return "0";
      }
      uint j = _i;
      uint len;
      
      while (j != 0) {
         len++;
         j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;
      
      while (_i != 0) {
         bstr[k--] = byte(uint8(48 + _i % 10));
         _i /= 10;
      }
      return string(bstr);//access local variable
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Ausgabe

0: string: 3

Die Rückgabeerklärung

Eine Solidity-Funktion kann optional sein returnErklärung. Dies ist erforderlich, wenn Sie einen Wert von einer Funktion zurückgeben möchten. Diese Anweisung sollte die letzte Anweisung in einer Funktion sein.

Wie im obigen Beispiel verwenden wir die Funktion uint2str, um einen String zurückzugeben.

In Solidity kann eine Funktion auch mehrere Werte zurückgeben. Siehe das folgende Beispiel -

pragma solidity ^0.5.0;

contract Test {
   function getResult() public view returns(uint product, uint sum){
      uint a = 1; // local variable
      uint b = 2;
      product = a * b;
      sum = a + b;
  
      //alternative return statement to return 
      //multiple values
      //return(a*b, a+b);
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Ausgabe

0: uint256: product 2
1: uint256: sum 3

Funktionsmodifikatoren werden verwendet, um das Verhalten einer Funktion zu ändern. Zum Beispiel, um einer Funktion eine Voraussetzung hinzuzufügen.

Zuerst erstellen wir einen Modifikator mit oder ohne Parameter.

contract Owner {
   modifier onlyOwner {
      require(msg.sender == owner);
      _;
   }
   modifier costs(uint price) {
      if (msg.value >= price) {
         _;
      }
   }
}

Der Funktionskörper wird dort eingefügt, wo das Sonderzeichen "_;" erscheint in der Definition eines Modifikators. Wenn also die Bedingung des Modifikators beim Aufrufen dieser Funktion erfüllt ist, wird die Funktion ausgeführt und andernfalls wird eine Ausnahme ausgelöst.

Siehe das folgende Beispiel -

pragma solidity ^0.5.0;

contract Owner {
   address owner;
   constructor() public {
      owner = msg.sender;
   }
   modifier onlyOwner {
      require(msg.sender == owner);
      _;
   }
   modifier costs(uint price) {
      if (msg.value >= price) {
         _;
      }
   }
}
contract Register is Owner {
   mapping (address => bool) registeredAddresses;
   uint price;
   constructor(uint initialPrice) public { price = initialPrice; }
   
   function register() public payable costs(price) {
      registeredAddresses[msg.sender] = true;
   }
   function changePrice(uint _price) public onlyOwner {
      price = _price;
   }
}

Ansichtsfunktionen stellen sicher, dass der Status nicht geändert wird. Eine Funktion kann als deklariert werdenview. Die folgenden Anweisungen, die in der Funktion vorhanden sind, werden als Änderung des Status betrachtet, und der Compiler gibt in solchen Fällen eine Warnung aus.

  • Statusvariablen ändern.

  • Ereignisse senden.

  • Andere Verträge erstellen.

  • Selbstzerstörung verwenden.

  • Ether über Anrufe senden.

  • Aufruf einer Funktion, die nicht als Ansicht oder rein markiert ist.

  • Verwenden von Anrufen auf niedriger Ebene.

  • Verwenden einer Inline-Assembly mit bestimmten Opcodes.

Getter-Methoden sind standardmäßig Ansichtsfunktionen.

Siehe das folgende Beispiel mit einer Ansichtsfunktion.

Beispiel

pragma solidity ^0.5.0;

contract Test {
   function getResult() public view returns(uint product, uint sum){
      uint a = 1; // local variable
      uint b = 2;
      product = a * b;
      sum = a + b; 
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Ausgabe

0: uint256: product 2
1: uint256: sum 3

Reine Funktionen stellen sicher, dass sie den Status nicht lesen oder ändern. Eine Funktion kann als deklariert werdenpure. Die folgenden Anweisungen, die in der Funktion vorhanden sind, werden als Lesen des Status betrachtet, und der Compiler gibt in solchen Fällen eine Warnung aus.

  • Zustandsvariablen lesen.

  • Zugriff auf Adresse (this) .balance oder <Adresse> .balance.

  • Zugriff auf eine der speziellen Variablen block, tx, msg (msg.sig und msg.data können gelesen werden).

  • Aufruf einer Funktion, die nicht als rein markiert ist.

  • Verwenden einer Inline-Assembly, die bestimmte Opcodes enthält.

Reine Funktionen können die Funktionen revert () und require () verwenden, um potenzielle Statusänderungen zurückzusetzen, wenn ein Fehler auftritt.

Siehe das folgende Beispiel mit einer Ansichtsfunktion.

Beispiel

pragma solidity ^0.5.0;

contract Test {
   function getResult() public pure returns(uint product, uint sum){
      uint a = 1; 
      uint b = 2;
      product = a * b;
      sum = a + b; 
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Ausgabe

0: uint256: product 2
1: uint256: sum 3

Die Fallback-Funktion ist eine spezielle Funktion, die einem Vertrag zur Verfügung steht. Es hat folgende Funktionen -

  • Es wird aufgerufen, wenn eine nicht vorhandene Funktion im Vertrag aufgerufen wird.

  • Es muss als extern gekennzeichnet werden.

  • Es hat keinen Namen.

  • Es hat keine Argumente

  • Es kann nichts zurückgeben.

  • Es kann eine pro Vertrag definiert werden.

  • Wenn nicht als zahlbar markiert, wird eine Ausnahme ausgelöst, wenn der Vertrag einfachen Äther ohne Daten erhält.

Das folgende Beispiel zeigt das Konzept einer Fallback-Funktion pro Vertrag.

Beispiel

pragma solidity ^0.5.0;

contract Test {
   uint public x ;
   function() external { x = 1; }    
}
contract Sink {
   function() external payable { }
}
contract Caller {
   function callTest(Test test) public returns (bool) {
      (bool success,) = address(test).call(abi.encodeWithSignature("nonExistingFunction()"));
      require(success);
      // test.x is now 1

      address payable testPayable = address(uint160(address(test)));

      // Sending ether to Test contract,
      // the transfer will fail, i.e. this returns false here.
      return (testPayable.send(2 ether));
   }
   function callSink(Sink sink) public returns (bool) {
      address payable sinkPayable = address(sink);
      return (sinkPayable.send(2 ether));
   }
}

Sie können mehrere Definitionen für denselben Funktionsnamen im selben Bereich haben. Die Definition der Funktion muss sich durch die Typen und / oder die Anzahl der Argumente in der Argumentliste unterscheiden. Sie können keine Funktionsdeklarationen überladen, die sich nur nach Rückgabetyp unterscheiden.

Das folgende Beispiel zeigt das Konzept einer Funktionsüberladung in Solidity.

Beispiel

pragma solidity ^0.5.0;

contract Test {
   function getSum(uint a, uint b) public pure returns(uint){      
      return a + b;
   }
   function getSum(uint a, uint b, uint c) public pure returns(uint){      
      return a + b + c;
   }
   function callSumWithTwoArguments() public pure returns(uint){
      return getSum(1,2);
   }
   function callSumWithThreeArguments() public pure returns(uint){
      return getSum(1,2,3);
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Klicken Sie zuerst auf die Schaltfläche callSumWithTwoArguments und dann auf die Schaltfläche callSumWithThreeArguments, um das Ergebnis anzuzeigen.

Ausgabe

0: uint256: 3
0: uint256: 6

Solidity bietet auch eingebaute mathematische Funktionen. Es folgen häufig verwendete Methoden -

  • addmod(uint x, uint y, uint k) returns (uint)- berechnet (x + y)% k, wobei die Addition mit beliebiger Genauigkeit durchgeführt wird und nicht bei 2 256 umläuft .

  • mulmod(uint x, uint y, uint k) returns (uint)- berechnet (x * y)% k, wobei die Addition mit beliebiger Genauigkeit durchgeführt wird und nicht bei 2 256 umläuft .

Das folgende Beispiel zeigt die Verwendung mathematischer Funktionen in Solidity.

Beispiel

pragma solidity ^0.5.0;

contract Test {   
   function callAddMod() public pure returns(uint){
      return addmod(4, 5, 3);
   }
   function callMulMod() public pure returns(uint){
      return mulmod(4, 5, 3);
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Klicken Sie zuerst auf die Schaltfläche callAddMod und dann auf die Schaltfläche callMulMod, um das Ergebnis anzuzeigen.

Ausgabe

0: uint256: 0
0: uint256: 2

Solidity bietet auch integrierte kryptografische Funktionen. Es folgen wichtige Methoden -

  • keccak256(bytes memory) returns (bytes32) - berechnet den Keccak-256-Hash der Eingabe.

  • sha256(bytes memory) returns (bytes32) - berechnet den SHA-256-Hash der Eingabe.

  • ripemd160(bytes memory) returns (bytes20) - RIPEMD-160-Hash der Eingabe berechnen.

  • sha256(bytes memory) returns (bytes32) - berechnet den SHA-256-Hash der Eingabe.

  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)- Stellen Sie die dem öffentlichen Schlüssel zugeordnete Adresse aus der Signatur der elliptischen Kurve wieder her oder geben Sie bei einem Fehler Null zurück. Die Funktionsparameter entsprechen den ECDSA-Werten der Signatur: r - erste 32 Bytes der Signatur; s: zweite 32 Bytes Signatur; v: letzte 1 Byte Signatur. Diese Methode gibt eine Adresse zurück.

Das folgende Beispiel zeigt die Verwendung der kryptografischen Funktion in Solidity.

Beispiel

pragma solidity ^0.5.0;

contract Test {   
   function callKeccak256() public pure returns(bytes32 result){
      return keccak256("ABC");
   }  
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Ausgabe

0: bytes32: result 0xe1629b9dda060bb30c7908346f6af189c16773fa148d3366701fbaa35d54f3c8

Das Abhebungsmuster stellt sicher, dass kein direkter Weiterleitungsanruf getätigt wird, der eine Sicherheitsbedrohung darstellt. Der folgende Vertrag zeigt die unsichere Verwendung des Weiterleitungsanrufs zum Senden von Äther.

pragma solidity ^0.5.0;

contract Test {
   address payable public richest;
   uint public mostSent;

   constructor() public payable {
      richest = msg.sender;
      mostSent = msg.value;
   }
   function becomeRichest() public payable returns (bool) {
      if (msg.value > mostSent) {
         // Insecure practice
         richest.transfer(msg.value);
         richest = msg.sender;
         mostSent = msg.value;
         return true;
      } else {
         return false;
      }
   }
}

Der oben genannte Vertrag kann in einen unbrauchbaren Zustand versetzt werden, indem der reichste Vertrag ein Vertrag mit fehlgeschlagener Fallback-Funktion wird. Wenn die Fallback-Funktion fehlschlägt, schlägt auch die Funktion areRichest () fehl und der Vertrag bleibt für immer bestehen. Um dieses Problem zu beheben, können wir das Abhebungsmuster verwenden.

Im Auszahlungsmuster setzen wir den ausstehenden Betrag vor jeder Überweisung zurück. Dadurch wird sichergestellt, dass nur der Anrufervertrag fehlschlägt.

pragma solidity ^0.5.0;

contract Test {
   address public richest;
   uint public mostSent;

   mapping (address => uint) pendingWithdrawals;

   constructor() public payable {
      richest = msg.sender;
      mostSent = msg.value;
   }
   function becomeRichest() public payable returns (bool) {
      if (msg.value > mostSent) {
         pendingWithdrawals[richest] += msg.value;
         richest = msg.sender;
         mostSent = msg.value;
         return true;
      } else {
         return false;
      }
   }
   function withdraw() public {
      uint amount = pendingWithdrawals[msg.sender];
      pendingWithdrawals[msg.sender] = 0;
      msg.sender.transfer(amount);
   }
}

Der eingeschränkte Zugang zu einem Vertrag ist eine gängige Praxis. Standardmäßig ist ein Vertragsstatus schreibgeschützt, sofern er nicht als öffentlich angegeben ist.

Wir können einschränken, wer den Vertragsstatus ändern oder die Funktionen eines Vertrags mithilfe von Modifikatoren aufrufen kann. Wir werden mehrere Modifikatoren erstellen und verwenden, wie unten erläutert -

  • onlyBy - Einmal für eine Funktion verwendet, kann nur der erwähnte Aufrufer diese Funktion aufrufen.

  • onlyAfter - Einmal für eine Funktion verwendet, kann diese Funktion nach einer bestimmten Zeitspanne aufgerufen werden.

  • costs - Einmal für eine Funktion verwendet, kann der Aufrufer diese Funktion nur aufrufen, wenn ein bestimmter Wert angegeben ist.

Beispiel

pragma solidity ^0.5.0;

contract Test {
   address public owner = msg.sender;
   uint public creationTime = now;

   modifier onlyBy(address _account) {
      require(
         msg.sender == _account,
         "Sender not authorized."
      );
      _;
   }
   function changeOwner(address _newOwner) public onlyBy(owner) {
      owner = _newOwner;
   }
   modifier onlyAfter(uint _time) {
      require(
         now >= _time,
         "Function called too early."
      );
      _;
   }
   function disown() public onlyBy(owner) onlyAfter(creationTime + 6 weeks) {
      delete owner;
   }
   modifier costs(uint _amount) {
      require(
         msg.value >= _amount,
         "Not enough Ether provided."
      );
      _;
      if (msg.value > _amount)
         msg.sender.transfer(msg.value - _amount);
   }
   function forceOwnerChange(address _newOwner) public payable costs(200 ether) {
      owner = _newOwner;
      if (uint(owner) & 0 == 1) return;        
   }
}

Der Vertrag in Solidität ähnelt einer Klasse in C ++. Ein Vertrag hat folgende Eigenschaften.

  • Constructor - Eine mit dem Schlüsselwort constructor deklarierte Sonderfunktion, die einmal pro Vertrag ausgeführt wird und beim Erstellen eines Vertrags aufgerufen wird.

  • State Variables - Variablen pro Vertrag zum Speichern des Vertragsstatus.

  • Functions - Funktionen pro Vertrag, mit denen die Statusvariablen geändert werden können, um den Status eines Vertrags zu ändern.

Sichtbarkeitsquantifizierer

Es folgen verschiedene Sichtbarkeitsquantifizierer für Funktionen / Zustandsvariablen eines Vertrags.

  • external- Externe Funktionen sollen durch andere Verträge aufgerufen werden. Sie können nicht für interne Anrufe verwendet werden. Um eine externe Funktion innerhalb des Vertrags aufzurufen, ist der Aufruf this.function_name () erforderlich. Zustandsvariablen können nicht als extern markiert werden.

  • public- Öffentliche Funktionen / Variablen können sowohl extern als auch intern verwendet werden. Für die Variable public state erstellt Solidity automatisch eine Getter-Funktion.

  • internal - Interne Funktionen / Variablen können nur intern oder von abgeleiteten Verträgen verwendet werden.

  • private - Private Funktionen / Variablen können nur intern und nicht einmal von abgeleiteten Verträgen verwendet werden.

Beispiel

pragma solidity ^0.5.0;

contract C {
   //private state variable
   uint private data;
   
   //public state variable
   uint public info;

   //constructor
   constructor() public {
      info = 10;
   }
   //private function
   function increment(uint a) private pure returns(uint) { return a + 1; }
   
   //public function
   function updateData(uint a) public { data = a; }
   function getData() public view returns(uint) { return data; }
   function compute(uint a, uint b) internal pure returns (uint) { return a + b; }
}
//External Contract
contract D {
   function readData() public returns(uint) {
      C c = new C();
      c.updateData(7);         
      return c.getData();
   }
}
//Derived Contract
contract E is C {
   uint private result;
   C private c;
   
   constructor() public {
      c = new C();
   }  
   function getComputedResult() public {      
      result = compute(3, 5); 
   }
   function getResult() public view returns(uint) { return result; }
   function getData() public view returns(uint) { return c.info(); }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus . Führen Sie verschiedene Vertragsmethoden aus. Für E.getComputedResult () gefolgt von E.getResult () wird -

Ausgabe

0: uint256: 8

Vererbung ist eine Möglichkeit, die Funktionalität eines Vertrags zu erweitern. Solidity unterstützt sowohl die Einzel- als auch die Mehrfachvererbung. Im Folgenden sind die wichtigsten Highlighs aufgeführt.

  • Ein abgeleiteter Vertrag kann auf alle nicht privaten Mitglieder zugreifen, einschließlich interner Methoden und Statusvariablen. Dies ist jedoch nicht zulässig.

  • Das Überschreiben von Funktionen ist zulässig, sofern die Funktionssignatur gleich bleibt. Bei unterschiedlichen Ausgabeparametern schlägt die Kompilierung fehl.

  • Wir können die Funktion eines Supervertrags mit dem Schlüsselwort super oder dem Namen des Supervertrags aufrufen.

  • Bei Mehrfachvererbung bevorzugt der Funktionsaufruf mit super den meisten abgeleiteten Vertrag.

Beispiel

pragma solidity ^0.5.0;

contract C {
   //private state variable
   uint private data;
   
   //public state variable
   uint public info;

   //constructor
   constructor() public {
      info = 10;
   }
   //private function
   function increment(uint a) private pure returns(uint) { return a + 1; }
   
   //public function
   function updateData(uint a) public { data = a; }
   function getData() public view returns(uint) { return data; }
   function compute(uint a, uint b) internal pure returns (uint) { return a + b; }
}
//Derived Contract
contract E is C {
   uint private result;
   C private c;
   constructor() public {
      c = new C();
   }  
   function getComputedResult() public {      
      result = compute(3, 5); 
   }
   function getResult() public view returns(uint) { return result; }
   function getData() public view returns(uint) { return c.info(); }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus . Führen Sie verschiedene Vertragsmethoden aus. Für E.getComputedResult () gefolgt von E.getResult () wird -

Ausgabe

0: uint256: 8

Der Konstruktor ist eine spezielle Funktion, die mit deklariert wurde constructorStichwort. Es ist eine optionale Funktion und wird zum Initialisieren von Statusvariablen eines Vertrags verwendet. Im Folgenden sind die wichtigsten Merkmale eines Konstruktors aufgeführt.

  • Ein Vertrag kann nur einen Konstruktor haben.

  • Ein Konstruktorcode wird beim Erstellen eines Vertrags einmal ausgeführt und zum Initialisieren des Vertragsstatus verwendet.

  • Nachdem ein Konstruktorcode ausgeführt wurde, wird der endgültige Code in der Blockchain bereitgestellt. Dieser Code enthält öffentliche Funktionen und Code, der über öffentliche Funktionen erreichbar ist. Konstruktorcode oder eine interne Methode, die nur vom Konstruktor verwendet wird, sind im endgültigen Code nicht enthalten.

  • Ein Konstruktor kann entweder öffentlich oder intern sein.

  • Ein interner Konstruktor markiert den Vertrag als abstrakt.

  • Falls kein Konstruktor definiert ist, ist im Vertrag ein Standardkonstruktor vorhanden.

pragma solidity ^0.5.0;

contract Test {
   constructor() public {}
}
  • Falls der Basisvertrag einen Konstruktor mit Argumenten hat, muss jeder abgeleitete Vertrag diese übergeben.

  • Der Basiskonstruktor kann auf folgende Weise direkt initialisiert werden:

pragma solidity ^0.5.0;

contract Base {
   uint data;
   constructor(uint _data) public {
      data = _data;   
   }
}
contract Derived is Base (5) {
   constructor() public {}
}
  • Der Basiskonstruktor kann indirekt auf folgende Weise initialisiert werden:

pragma solidity ^0.5.0;

contract Base {
   uint data;
   constructor(uint _data) public {
      data = _data;   
   }
}
contract Derived is Base {
   constructor(uint _info) Base(_info * _info) public {}
}
  • Direkte und indirekte Methoden zum Initialisieren des Basisvertragskonstruktors sind nicht zulässig.

  • Wenn der abgeleitete Vertrag keine Argumente an den Basisvertragskonstruktor weiterleitet, wird der abgeleitete Vertrag abstrakt.

Abstract Vertrag ist ein Vertrag, der mindestens eine Funktion ohne Implementierung enthält. Ein solcher Vertrag wird als Basisvertrag verwendet. Im Allgemeinen enthält ein abstrakter Vertrag sowohl implementierte als auch abstrakte Funktionen. Der abgeleitete Vertrag implementiert die abstrakte Funktion und verwendet die vorhandenen Funktionen nach Bedarf.

Falls ein abgeleiteter Vertrag die abstrakte Funktion nicht implementiert, wird dieser abgeleitete Vertrag als abstrakt markiert.

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie die abstrakten Verträge in Solidity funktionieren.

pragma solidity ^0.5.0;

contract Calculator {
   function getResult() public view returns(uint);
}
contract Test is Calculator {
   function getResult() public view returns(uint) {
      uint a = 1;
      uint b = 2;
      uint result = a + b;
      return result;
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Ausgabe

0: uint256: 3

Schnittstellen ähneln abstrakten Verträgen und werden mit erstellt interfaceStichwort. Im Folgenden sind die wichtigsten Merkmale einer Schnittstelle aufgeführt.

  • Die Schnittstelle kann bei der Implementierung keine Funktion haben.

  • Funktionen einer Schnittstelle können nur vom Typ extern sein.

  • Schnittstelle kann keinen Konstruktor haben.

  • Schnittstelle kann keine Zustandsvariablen haben.

  • Die Schnittstelle kann enum haben, Strukturen, auf die mit der Punktnotation des Schnittstellennamens zugegriffen werden kann.

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie die Schnittstelle in Solidity funktioniert.

pragma solidity ^0.5.0;

interface Calculator {
   function getResult() external view returns(uint);
}
contract Test is Calculator {
   constructor() public {}
   function getResult() external view returns(uint){
      uint a = 1; 
      uint b = 2;
      uint result = a + b;
      return result;
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Note - Wählen Sie Test aus der Dropdown-Liste, bevor Sie auf die Schaltfläche Bereitstellen klicken.

Ausgabe

0: uint256: 3

Bibliotheken ähneln Verträgen, sind jedoch hauptsächlich für die Wiederverwendung vorgesehen. Eine Bibliothek enthält Funktionen, die andere Verträge aufrufen können. Solidity hat bestimmte Einschränkungen bei der Nutzung einer Bibliothek. Im Folgenden sind die wichtigsten Merkmale einer Solidity Library aufgeführt.

  • Bibliotheksfunktionen können direkt aufgerufen werden, wenn sie den Status nicht ändern. Das bedeutet, dass reine oder Ansichtsfunktionen nur von außerhalb der Bibliothek aufgerufen werden können.

  • Die Bibliothek kann nicht zerstört werden, da davon ausgegangen wird, dass sie zustandslos ist.

  • Eine Bibliothek kann keine Statusvariablen haben.

  • Eine Bibliothek kann kein Element erben.

  • Eine Bibliothek kann nicht vererbt werden.

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie eine Bibliothek in Solidity funktioniert.

pragma solidity ^0.5.0;

library Search {
   function indexOf(uint[] storage self, uint value) public view returns (uint) {
      for (uint i = 0; i < self.length; i++) if (self[i] == value) return i;
      return uint(-1);
   }
}
contract Test {
   uint[] data;
   constructor() public {
      data.push(1);
      data.push(2);
      data.push(3);
      data.push(4);
      data.push(5);
   }
   function isValuePresent() external view returns(uint){
      uint value = 4;
      
      //search if value is present in the array using Library function
      uint index = Search.indexOf(data, value);
      return index;
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Note - Wählen Sie Test aus der Dropdown-Liste, bevor Sie auf die Schaltfläche Bereitstellen klicken.

Ausgabe

0: uint256: 3

Verwenden von For

Die Richtlinie using A for B; kann verwendet werden, um Bibliotheksfunktionen der Bibliothek A an einen bestimmten Typ B anzuhängen. Diese Funktionen verwenden den Aufrufertyp als ersten Parameter (identifiziert mit self).

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie eine Bibliothek in Solidity funktioniert.

pragma solidity ^0.5.0;

library Search {
   function indexOf(uint[] storage self, uint value) public view returns (uint) {
      for (uint i = 0; i < self.length; i++)if (self[i] == value) return i;
      return uint(-1);
   }
}
contract Test {
   using Search for uint[];
   uint[] data;
   constructor() public {
      data.push(1);
      data.push(2);
      data.push(3);
      data.push(4);
      data.push(5);
   }
   function isValuePresent() external view returns(uint){
      uint value = 4;      
      
      //Now data is representing the Library
      uint index = data.indexOf(value);
      return index;
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Note - Wählen Sie Test aus der Dropdown-Liste, bevor Sie auf die Schaltfläche Bereitstellen klicken.

Ausgabe

0: uint256: 3

Solidity bietet eine Option zur Verwendung der Assemblersprache zum Schreiben von Inline-Assemblierungen im Solidity-Quellcode. Wir können auch einen eigenständigen Assemblycode schreiben, der dann in Bytecode konvertiert wird. Standalone Assembly ist eine Zwischensprache für einen Solidity-Compiler und konvertiert den Solidity-Code in eine Standalone-Assembly und anschließend in Bytecode. Wir können dieselbe Sprache verwenden, die in Inline Assembly verwendet wird, um Code in eine eigenständige Assembly zu schreiben.

Inline-Montage

Inline-Assembler-Code kann innerhalb der Solidity-Codebasis verschachtelt werden, um eine genauere Kontrolle über EVM zu erhalten. Er wird insbesondere beim Schreiben der Bibliotheksfunktionen verwendet.

Ein Assembler-Code wird unter geschrieben assembly { ... } Block.

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie eine Bibliothek in Solidity funktioniert.

pragma solidity ^0.5.0;

library Sum {   
   function sumUsingInlineAssembly(uint[] memory _data) public pure returns (uint o_sum) {
      for (uint i = 0; i < _data.length; ++i) {
         assembly {
            o_sum := add(o_sum, mload(add(add(_data, 0x20), mul(i, 0x20))))
         }
      }
   }
}
contract Test {
   uint[] data;
   
   constructor() public {
      data.push(1);
      data.push(2);
      data.push(3);
      data.push(4);
      data.push(5);
   }
   function sum() external view returns(uint){      
      return Sum.sumUsingInlineAssembly(data);
   }
}

Führen Sie das obige Programm mit den im Kapitel Solidity First Application beschriebenen Schritten aus .

Note - Wählen Sie Test aus der Dropdown-Liste, bevor Sie auf die Schaltfläche Bereitstellen klicken.

Ausgabe

0: uint256: 15

Event ist ein vererbbares Vertragsmitglied. Wenn ein Ereignis ausgegeben wird, werden die in Transaktionsprotokollen übergebenen Argumente gespeichert. Diese Protokolle werden in der Blockchain gespeichert und sind über die Adresse des Vertrags zugänglich, bis der Vertrag in der Blockchain vorhanden ist. Auf ein generiertes Ereignis kann nicht innerhalb von Verträgen zugegriffen werden, auch nicht innerhalb desjenigen, der sie erstellt und ausgegeben hat.

Ein Ereignis kann mit dem Schlüsselwort event deklariert werden.

//Declare an Event
event Deposit(address indexed _from, bytes32 indexed _id, uint _value);

//Emit an event
emit Deposit(msg.sender, _id, msg.value);

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie ein Ereignis in Solidity funktioniert.

Erstellen Sie zuerst einen Vertrag und senden Sie ein Ereignis aus.

pragma solidity ^0.5.0;

contract Test {
   event Deposit(address indexed _from, bytes32 indexed _id, uint _value);
   function deposit(bytes32 _id) public payable {      
      emit Deposit(msg.sender, _id, msg.value);
   }
}

Greifen Sie dann im JavaScript-Code auf das Ereignis des Vertrags zu.

var abi = /* abi as generated using compiler */;
var ClientReceipt = web3.eth.contract(abi);
var clientReceiptContract = ClientReceipt.at("0x1234...ab67" /* address */);

var event = clientReceiptContract.Deposit(function(error, result) {
   if (!error)console.log(result);
});

Es sollte Details ähnlich wie folgt drucken:

Ausgabe

{
   "returnValues": {
      "_from": "0x1111...FFFFCCCC",
      "_id": "0x50...sd5adb20",
      "_value": "0x420042"
   },
   "raw": {
      "data": "0x7f...91385",
      "topics": ["0xfd4...b4ead7", "0x7f...1a91385"]
   }
}

Solidity bietet verschiedene Funktionen zur Fehlerbehandlung. Wenn ein Fehler auftritt, wird der Status im Allgemeinen auf seinen ursprünglichen Status zurückgesetzt. Andere Überprüfungen sollen den unbefugten Zugriff auf Code verhindern. Im Folgenden finden Sie einige wichtige Methoden zur Fehlerbehandlung:

  • assert(bool condition)- Falls die Bedingung nicht erfüllt ist, verursacht dieser Methodenaufruf einen ungültigen Opcode und alle am Status vorgenommenen Änderungen wurden zurückgesetzt. Diese Methode ist für interne Fehler anzuwenden.

  • require(bool condition)- Falls die Bedingung nicht erfüllt ist, kehrt dieser Methodenaufruf in den ursprünglichen Zustand zurück. - Diese Methode ist für Fehler in Eingängen oder externen Komponenten zu verwenden.

  • require(bool condition, string memory message)- Falls die Bedingung nicht erfüllt ist, kehrt dieser Methodenaufruf in den ursprünglichen Zustand zurück. - Diese Methode ist für Fehler in Eingängen oder externen Komponenten zu verwenden. Es bietet eine Option zum Bereitstellen einer benutzerdefinierten Nachricht.

  • revert() - Diese Methode bricht die Ausführung ab und setzt alle am Status vorgenommenen Änderungen zurück.

  • revert(string memory reason)- Diese Methode bricht die Ausführung ab und setzt alle am Status vorgenommenen Änderungen zurück. Es bietet eine Option zum Bereitstellen einer benutzerdefinierten Nachricht.

Beispiel

Versuchen Sie den folgenden Code, um zu verstehen, wie die Fehlerbehandlung in Solidity funktioniert.

pragma solidity ^0.5.0;

contract Vendor {
   address public seller;
   modifier onlySeller() {
      require(
         msg.sender == seller,
         "Only seller can call this."
      );
      _;
   }
   function sell(uint amount) public payable onlySeller { 
      if (amount > msg.value / 2 ether)
         revert("Not enough Ether provided.");
      // Perform the sell operation.
   }
}

Wenn "Zurücksetzen" aufgerufen wird, werden die hexadezimalen Daten wie folgt zurückgegeben.

Ausgabe

0x08c379a0                     // Function selector for Error(string)
0x0000000000000000000000000000000000000000000000000000000000000020 // Data offset
0x000000000000000000000000000000000000000000000000000000000000001a // String length
0x4e6f7420656e6f7567682045746865722070726f76696465642e000000000000 // String data