Der Try/Catch -Syntax eingeführt in 0,6,0 ist wohl der größte Sprung in die Handhabung der Fehler, da die Fehlern für die Fehlgeschlagenheit für Strings für festgelegt ist zurückkehren Und erfordern wurden in v0.4.22 freigelassen. Beide versuchen Und fangen sind zurückhaltende Schlüsselwörter Seit v0.5.9 Und jetzt können wir sie verwenden, um Fehler in den Umgang mit extern Funktionsaufrufe, ohne die vollständige Transaktion zurückzurollen (Statusänderungen in der aufgerufenen Funktion sind weiterhin zurückgeführt, die in der Aufruffunktion sind jedoch nicht).
Wir bewegen uns einen Schritt vom puristischen “All-or-Nothing” -Ansatz in einem Transaktionslebenszyklus, das das von uns oft gewünschte praktische Verhalten abbaut.
Umgang mit externen Anruffehlern
Mit der Anweisung Try/Catch können Sie fehlgeschlagen reagieren extern Anrufe und Vertragserstellung Anrufe, also können Sie es nicht verwenden für intern Funktionsaufrufe. Beachten Das..
Das folgende Beispiel zeigt, wie Try/Catch in einem Werksmuster verwendet wird, bei dem die Vertragserstellung möglicherweise fehlschlägt. Die folgende Wohltätigkeitsorganisation Der Vertrag erfordert eine obligatorische Adresse des Eigentums _Eigentümer in seinem Konstruktor.
pragma solidity ^0.6.1; contract CharitySplitter { address public owner; constructor (address _owner) public { require(_owner != address(0), "no-owner-provided"); owner = _owner; } }
Es gibt einen Fabrikvertrag – CharitySplitterFactory das wird verwendet, um Instanzen von zu erstellen und zu verwalten Wohltätigkeitsorganisation. In der Fabrik können wir das einwickeln Neue Wohltätigkeitsorganisation (Wohltätigkeitseigner) In einem Versuch/Fang als Fehlsicherung, wenn dieser Konstruktor aufgrund eines leeren möglicherweise fehlschlägt Wohltätigkeitsmobiliener bestanden werden.
pragma solidity ^0.6.1; import "./CharitySplitter.sol"; contract CharitySplitterFactory { mapping (address => CharitySplitter) public charitySplitters; uint public errorCount; event ErrorHandled(string reason); event ErrorNotHandled(bytes reason); function createCharitySplitter(address charityOwner) public { try new CharitySplitter(charityOwner) returns (CharitySplitter newCharitySplitter) { charitySplitters[msg.sender] = newCharitySplitter; } catch { errorCount++; } } }
Beachten Sie, dass mit Try/Catch nur Ausnahmen im externen Anruf selbst erfasst werden. Fehler im Ausdruck werden nicht gefangen, zum Beispiel, wenn der Eingabeparameter für die Neue Wohltätigkeitsorganisation Ist selbst Teil eines internen Anrufs, werden alle Fehler, die es errichtet, nicht gefangen. Probe, die dieses Verhalten demonstriert, ist das modifizierte CreateCharitySsplitter Funktion. Hier die Wohltätigkeitsorganisation Der Konstruktoreingangsparameter wird dynamisch aus einer anderen Funktion abgerufen – GetCharityowner. Wenn diese Funktion zurückkehrt, in diesem Beispiel mit “Umweichend für die Prüfung”Das wird in der Aussage/Fangerklärung nicht gefangen.
function createCharitySplitter(address _charityOwner) public { try new CharitySplitter(getCharityOwner(_charityOwner, false)) returns (CharitySplitter newCharitySplitter) { charitySplitters[msg.sender] = newCharitySplitter; } catch (bytes memory reason) { ... } } function getCharityOwner(address _charityOwner, bool _toPass) internal returns (address) { require(_toPass, "revert-required-for-testing"); return _charityOwner; }
Abrufen der Fehlermeldung
Wir können die Versuchs-/Fanglogik in der weiter erweitern CreateCharitySsplitter Funktion zum Abrufen der Fehlermeldung, wenn einer von einem Fehler emittiert wurde zurückkehren oder erfordern und geben Sie es in einer Veranstaltung aus. Es gibt zwei Möglichkeiten, dies zu erreichen:
1. Fehler aufnehmen (String -Speichergrund)
function createCharitySplitter(address _charityOwner) public { try new CharitySplitter(_charityOwner) returns (CharitySplitter newCharitySplitter) { charitySplitters[msg.sender] = newCharitySplitter; } catch Error(string memory reason) { errorCount++; CharitySplitter newCharitySplitter = new CharitySplitter(msg.sender); charitySplitters[msg.sender] = newCharitySplitter; // Emitting the error in event emit ErrorHandled(reason); } catch { errorCount++; } }
Das folgende Ereignis auf einem fehlgeschlagenen Konstruktor erfordern Fehler:
CharitySplitterFactory.ErrorHandled( reason: 'no-owner-provided' (type: string) )
2. Catch (Bytes Memory Grund)
function createCharitySplitter(address charityOwner) public { try new CharitySplitter(charityOwner) returns (CharitySplitter newCharitySplitter) { charitySplitters[msg.sender] = newCharitySplitter; } catch (bytes memory reason) { errorCount++; emit ErrorNotHandled(reason); } }
Das folgende Ereignis auf einem fehlgeschlagenen Konstruktor erfordern Fehler:
CharitySplitterFactory.ErrorNotHandled( reason: hex'08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000116e6f2d6f776e65722d70726f7669646564000000000000000000000000000000' (type: bytes)
Die beiden oben genannten Methoden zum Abrufen der Fehlerzeichenfolge erzeugen ein ähnliches Ergebnis. Der Unterschied besteht darin, dass die zweite Methode die Fehlerzeichenfolge nicht abgibt. Der Vorteil der zweiten Methode besteht darin, dass sie auch ausgeführt wird, wenn ABI -Dekodierung der Fehlerzeichenfolge fehlschlägt oder wenn kein Grund angegeben wurde.
Zukünftige Pläne
Es gibt Pläne, Unterstützung für Fehlertypen zu veröffentlichen, was bedeutet, dass wir Fehler auf ähnliche Weise deklarieren können, die es uns ermöglichen, verschiedene Arten von Fehlern zu fangen, beispielsweise:
catch CustomErrorA(uint data1) { … } catch CustomErrorB(uint[] memory data2) { … } catch {}
