Lieferung von Gas vom Vertrag bis zur Ausführung der Funktion

Nehmen wir an, ich habe so etwas

function usuallyCheapFunction() external {
    ... do something cheap...
    if(rareCondition == true) {
        expensiveCleanupFunction();
    }
}

function expensiveCleanupFunction() internal {
   ... shuffle around some storage ...
}

Benutzer würden normalerweiseCheapFunction() aufrufen, um etwas zu tun, und einen günstigen Transaktionspreis erwarten. Manchmal muss der Vertrag eine teure Bereinigung durchführen - ist es in diesem Fall möglich, Gas aus dem Vertrag zu liefern, um teuerCleanupFunction() aufzurufen, damit der Aufruf keinen Gasmangel verursacht? Wenn ja, wie würde diese aussehen?

Antworten (2)

Derzeit ist es nicht möglich, Gas aus dem Guthaben des Vertrages zu bezahlen, obwohl sich dies in Zukunft ändern kann, aber der intelligente Vertrag kann den Herausgeber der Gastransaktion erstatten, der für die Haushaltsfunktion aufgewendet wurde:

modifier refundable () {
    uint256 gasBefore = gasleft ();
    _;
    tx.origin.send (tx.gasprice * (gasleft () - gasBefore));
}

function expensiveCleanupFunction() refundable internal {
    ... shuffle around some storage ...
}

Dies wird jedoch kein Gas zurückerstatten, falls Smart Contract nicht genug Ether hat. Wenn Sie auch bei unzureichendem Guthaben eine Rückerstattung benötigen, gehen Sie folgendermaßen vor:

mapping (address => uint256) private refundBalance;

modifier refundable () {
    uint256 gasBefore = gasleft ();
    _;
    uint256 toRefund = tx.gasprice * (gasleft () - gasBefore);
    if (!tx.origin.send (toRefund))
        refundBalance [tx.origin] += toRefund;
}

function withdraw () public {
    uint256 toTransfer = refundBalance [msg.sender];
    refundBalance [msg.sender] = 0;
    msg.sender.transfer (toTransfer);
}

function expensiveCleanupFunction () refundable internal {
    ... shuffle around some storage ...
}

Falls die sofortige Rückerstattung fehlschlägt, erhöhen Smart Contracts das Rückerstattungsguthaben der Benutzer, und sobald das Smart Contract-Guthaben wiederhergestellt ist, kann der Benutzer seine Rückerstattung zurückziehen.

Dies ist nicht in einer einzigen Transaktion möglich, da jede Operation in Solidity zu einem Opcode herunterkompiliert wird und jeder Opcode mit Kosten verbunden ist. Alle diese Kosten sind größer als 0, daher gibt es keine Möglichkeit, eine Transaktion zu „bereinigen“ und ihr zu erlauben, mehr Gas zu verbrauchen (dh mehr Opcodes zu generieren).

Wenn Sie auf Szenarien stoßen, in denen dies der Fall ist, ist es im Allgemeinen am besten, den Vertrag so umzugestalten, dass er sich so verhält, dass bei einer einzigen Transaktion nicht so viel Gas verbraucht wird. Wenn möglich, können Sie eine einzelne Funktion in mehrere Funktionen aufteilen, die an verschiedenen Stellen (verschiedenen Transaktionen) aufgerufen werden und den Vertragsstand speichern.

In diesem Repo finden Sie eine Liste der Opcode-Kosten.

Ich bin mir nicht sicher, ob ich Ihre Antwort verstehe. Wollen Sie damit sagen, dass die Kosten für die Ausführung von "normale billige Funktion" immer gleich sind, unabhängig davon, ob rareCondition == trueoder nicht? Außerdem möchte ich die Transaktion nicht "aufräumen" - ich möchte manchmal einen teuren Code ausführen und zusätzliches Gas aus dem Vertrag liefern, um das vom Anrufer gesendete Gas zu ergänzen.
Nein, die Kosten für usuallyCheapFunctionwerden schwanken, wenn rareConidition == true(der Benutzer muss mehr Gas bezahlen, damit die Transaktion nicht fehlschlägt, wenn die seltene Bedingung ausgelöst wird). Und im Moment kann der Vertrag kein zusätzliches Gas liefern. Dies ist ein potenzielles Feature in Serenity, wenn es herauskommt, aber so wie es jetzt aussieht, ist dies nicht möglich. Weitere Informationen finden Sie in diesem Blogbeitrag von Vitalik.
Welche Refactoring-Optionen habe ich in diesem Fall, um sicherzustellen, dass kostspieligeCleanupFunction() ausgeführt wird (kann irgendwann asynchron sein), ohne mich auf eine externe vertrauenswürdige Entität zu verlassen?
Es hängt wirklich davon ab, was es tun soll. Wenn es sich bei der Transaktion um die Person handelt, die ETH/Token erhält, können Sie die Token im Vertrag sperren, bis die Person die Funktion in einer zweiten Transaktion aufruft. Wenn es um Zustandsübergänge geht, versuchen Sie die Speicherung Ihres Vertrages zu optimieren. Im Allgemeinen ist es am besten, in Solidity so wenig wie möglich zu tun, um die Kosten zu minimieren und die Sicherheit zu maximieren.