Ist es eine gute Praxis, jedes Mal ein Ereignis zu protokollieren, wenn ich Solidity einwerfe?

In Solidity (0.3.2) ist mir bewusst, dass es keine Möglichkeit gibt, bestimmte Ausnahmen auszulösen. (Alles ist ein invalid JUMPFehler.) Es scheint vorteilhaft zu sein, bestimmte Fehler protokollieren zu können. Ist es sinnvoll, ein Fehlerereignis zu erstellen, das vor jeder Ausnahme ausgelöst wird? Gibt es Nachteile, an die ich nicht denke?

event Error(string message);

...

if(msg.sender != owner) {
  Error("User not authorized");
  throw;
}

BEARBEITEN: Es scheint, dass das Ereignis überhaupt nicht protokolliert wird, wenn die Transaktion fehlschlägt. Kann jemand bestätigen?

Antworten (2)

Mit einer Ausnahme, wie bei throw, werden alle Effekte (einschließlich Ereignisse) einer Transaktion rückgängig gemacht, mit Ausnahme der Zahlung an den Miner. Es würde also keinen Vorteil bringen, ein Ereignis vor einer throw.


Mögliche Alternative

Wenn keine vollständige Wiederherstellung über eine Ausnahme erforderlich ist , kann ein Fehlercode verwendet werden.

Beispiel:

contract C {
  function foo() returns(int) {
    if(msg.sender != owner) {
      Error("User not authorized")
      return -1111;  // some error code
    }
    // sender is authorized so do stuff
  }
}

Auf Ereignisse kann nicht über Verträge zugegriffen werden, daher ist die Fehlermeldung eher für das Frontend bestimmt. Wenn die Nachricht nur für das Frontend bestimmt ist, erwägen Sie die Verwendung eines Musters von eth_callvor einem eth_sendTransaction (Anruf vs. sendTx wird hier erklärt).

Das eth_callBefore eth_sendTransaction-Muster würde wie dieser Frontend-JavaScript-Code aussehen:

// `contract` is an instance, from web3.eth.contract(...).at(...)

if (contract.foo.call({from: eth.accounts[0]...) === -1111) {
  // example only of how error could be dealt with
  alert("User not authorized");  
  return;
}

// user should now be authorized (though it is possible another transaction may have changed `owner` in contract `C` after above eth_call and before this upcoming eth_sendTransaction)
contract.foo.sendTransaction({from: eth.accounts[0]......)

Allerdings kann es Fälle geben, in denen das Erstellen eines Fehlerereignisses erwünscht ist. Wenn Ihre DApp beispielsweise Analysen darüber wünscht, wie viele Fehler aufgetreten sind, wie viele nicht autorisierte Fehler sind usw., könnte ein Fehlerereignis der richtige Weg sein.

BEARBEITEN: Wenn https://github.com/ethereum/solidity/issues/1686 implementiert ist, würde das Beispiel in der Frage so aussehen:

require(msg.sender == owner, "User not authorized");
In Bezug auf mögliche Alternative ist der Nachteil dieses Ansatzes: Der Anrufer muss für die erfolglose Transaktion bezahlen. Natürlich wäre es manchmal wünschenswert, den Anrufer zu "belasten" und einen aussagekräftigen Status zurückzugeben, also wäre es eine Frage der Wahl.

Ich habe festgestellt, dass die Behandlung von Ereignissen durch einen Modifikator im unteren Beispiel ohne Throw ziemlich einfach funktioniert.

modifier Modifier_Name() {
        if (Some_Check == Bool) {
            Event(Event_Arg_Type);
            Function_Access_Bool = Bool;
        }
        _;
    }

function Function_Name(Function_Args) public
     Modifier_Name()
     returns bool (success) 
     {
      if (Function_Access_Bool == false) {
          return false;
      }
      else
      {
        ...Desired_Code...;
          return true;
      }
  }