Wie ist die Ausführungsreihenfolge für mehrere Funktionsmodifikatoren? [Duplikat]

Ich weiß nicht, warum niemand diese Frage stellt (ich habe meine Hausaufgaben gemacht und tonnenweise gegoogelt, um eine Antwort zu finden), aber es fällt mir schwer zu verstehen, wie Funktionsmodifikatoren tatsächlich funktionieren.

Sicher, es ist trivial, wenn Sie nur einen Modifikator verwenden, oder wenn Sie die _Notation immer am Ende verwenden. Aber ich stoße auf Code, der in etwa so aussieht:

modifier modA {
  // verify something
  _;
  // verify something
  _;
}
modifier modB {
  // verify something
  _;
  // verify something
  _;
}
modifier modC {
  // verify something
  _;
  // verify something
  _;
}

function Fun() modA modB modC {
  // Do something
}

Dann wird mir endlich klar, dass ich keine Ahnung hatte, was darunter vor sich geht.

Wie soll das im obigen Fall funktionieren? Ein Blick in die Dokumentation hilft nicht wirklich weiter, da dort nur steht, dass die Modifikatoren einfach das _durch den Funktionscode ersetzen. Aber was ist, wenn es mehrere davon gibt?

Wenn wir also von modAzu gehen modB, wird das _durch den nächsten Modifikator ersetzt? Was meinen sie mit "durch die ursprüngliche Funktion ersetzt werden"?

Antworten (2)

Ich denke, dass ein guter Weg, um zu verstehen, was passiert, darin besteht, damit zu experimentieren

Ich habe diesen Vertrag in Remix erstellt, um einige meiner Annahmen darüber zu testen/zu beweisen, was mit Modifikatoren passiert:


pragma solidity ^0.4.18;

contract modifierTest {
    uint public modState1;
    uint public modState2;
    uint public modState3;

    modifier modA() {
        modState1 = modState1 + 1;
        _;
    }

    modifier modB() {
        modState2 = modState2 + 1;
        _;
        modState2 = modState2 + 1;
        _;
    }

    function func() public modA modB {
        modState3 = modState3 + 1;
    }
}

Anfänglich werden alle Zustandsvariablen des Vertrags auf 0 gesetzt/standardmäßig auf 0 gesetzt.

Nachdem wir die Funktion func ausgeführt und die Zustandsvariablen untersucht haben, sehen wir das folgende Ergebnis:


modState1 - uint256: 1
modState2 - uint256: 2
modState3 - uint256: 2
  • Wir können sehen, dass der Modifikator modA nur einmal ausgeführt wurde.
  • Wir können sehen, dass der Modifikator modB nur einmal ausgeführt wurde.
  • Wir können sehen, dass mehr als ein _; ist gültige Syntax
  • Wir können sehen, dass die Funktion func zweimal aufgerufen wurde

Daraus können wir verstehen, dass die ; im Modifikator *modA* durch den Code des Modifikators *modB* ersetzt wurde und dass die * ;*s im Hauptteil des Modifikators modB durch den Code der func - Funktion ersetzt wurden.

Wenn wir also von modA zu modB gehen, wird das _ durch den nächsten Modifikator ersetzt? Was meinen sie mit "durch die ursprüngliche Funktion ersetzt werden"?

Hoffentlich zeigt dieses Beispiel, wie das _ durch den nächsten Modifikator ersetzt wird und dass das _ des letzten Modifikators durch den Code der Funktion ersetzt wird.

Wichtig zu beachten ist, dass funczweimal aufgerufen wird, weil Sie mehrere _;drin modBhaben und nicht, weil es mehrere Modifikatoren gibt.

Angenommen, eine vertragsweite Variable „a“ mit einem Wert von „0“ und eine Funktion F mit einem Modifikator M:

function F() M() {
   a = 1;
}

modifier M() {
   if (a == 1) throw;
   _
}

das wird nicht werfen. Aber diese Version:

modifier M() {
   _
   if (a == 1) throw;
}

wird werfen. Stellen Sie sich Modifikatoren als Codeersatz (Vorkompilierung in C++-Begriffen) im Gegensatz zu "Aufrufen" vor. Modifikatoren sind keine Funktionen. Es ist genau so, als ob die Funktion F in jedem Fall so aussehen würde, was, wenn Sie davon ausgehen, dass 'a' einen Wert von '0' hat, um zu starten, zwei unterschiedliche Verhaltensweisen hat:

function F() {
   if (a == 1) throw;
   a = 1;
}

und

function F() {
   a = 1;
   if (a == 1) throw;
}

Um es herauszufinden, egal wie kompliziert, kopieren Sie einfach den Modifikatorcode an die richtige Stelle in der zu ändernden Funktion. Möglicherweise müssen Sie viele Ebenen tief kopieren, aber das ist es, was der Precompiler tut.

Ich bin überrascht, zwei _in Ihren Beispielen zu sehen. Ich wusste nicht, dass du das kannst. Es scheint mir eine sehr schlechte Praxis zu sein, _zweimal in einem Modifikator zu verwenden. Es macht den Code enorm schwer konzeptionell zu verstehen. Zumindest tut es das für mich.

Ich habe online ein paar Beispiele gesehen, bei denen die Modifikatoren mehrere _s haben. Hier ist einer: ethereum.stackexchange.com/a/5864/21958 - Ich denke auch, dass Sie verstehen, was Sie sagen, aber könnten Sie die Antwort erläutern, um sicherzugehen? Wie ich verstanden habe, sagen Sie, dass die Funktion F () nicht ausgeführt wird, bis sie alle Modifikatoren M1 (), M2 (), M3 () nacheinander durchläuft, wobei M1 () zuerst F () ersetzt. Ersetzen Sie dann das Ergebnis durch M2() und so weiter. Und erst wenn es den letzten Modifikator erreicht, führt es die Funktion tatsächlich aus?
Nehmen Sie den Körper des Codes in F und ersetzen Sie den Unterstrich von M damit. Nehmen Sie dann das Ergebnis if that und es wird buchstäblich zum Hauptteil von F. Dies alles geschieht während des Kompilierungsschritts, nicht zur Laufzeit. Hilft das?