Suministro de gas desde el contrato hasta la ejecución de la función

digamos que tengo algo como esto

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

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

Los usuarios llamarían a usualCheapFunction() para hacer algo, esperando un precio de transacción económico. A veces, el contrato debe realizar una limpieza costosa. ¿Es posible en este caso suministrar gas del contrato para llamar a la función de limpieza costosa () para que la llamada no cause una falta de gas? Si es así, ¿cómo se vería esto?

Respuestas (2)

Por ahora, no es posible pagar el gas del saldo del contrato, aunque esto puede cambiar en el futuro, pero el contrato inteligente puede reembolsar al editor de transacciones de gas gastado en la función de limpieza:

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

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

Sin embargo, esto no reembolsará el gas en caso de que el contrato inteligente no tenga suficiente éter. Si necesita reembolsar incluso en caso de saldo insuficiente, haga algo como esto:

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 ...
}

Entonces, en caso de que falle el reembolso instantáneo, los contratos inteligentes incrementan el saldo de reembolso de los usuarios, y una vez que se reabastece el saldo del contrato inteligente, el usuario podrá retirar su reembolso.

No es posible hacer esto en una sola transacción, ya que cada operación en Solidity se compila en un código de operación y cada código de operación tiene un costo asociado. Todos estos costos son mayores que 0, por lo que no hay forma de 'limpiar' una transacción y permitirle usar más gas (es decir, generar más códigos de operación).

En general, si se encuentra con escenarios en los que este es el caso, es mejor refactorizar el contrato para que se comporte de tal manera que no use tanto gas en una sola transacción. Si es posible, puede dividir una sola función en múltiples funciones, llamadas en diferentes puntos (diferentes transacciones), que guardan el estado del contrato.

Consulte este repositorio para obtener una lista de costos de códigos de operación.

No estoy seguro de entender tu respuesta. ¿Está diciendo que el costo de ejecutar usualmenteCheapFunction es siempre el mismo, independientemente de si rareCondition == trueo no? Además, no quiero 'limpiar la transacción': a veces quiero ejecutar un código costoso y suministrar gas adicional del contrato para complementar el gas enviado por la persona que llama.
No, el costo de usuallyCheapFunctionfluctuará si rareConidition == true(el usuario debe pagar más gasolina para que la transacción no falle si se activa la condición rara). Y, en este momento, el contrato no puede suministrar gas extra. Esta es una característica potencial en Serenity cuando salga, pero tal como está ahora, esto no es posible. Eche un vistazo a esta publicación de blog de Vitalik para obtener más información.
En ese caso, ¿qué opciones de refactorización tengo para asegurarme de que se está ejecutando la función de limpieza costosa () (en algún momento, puede ser asíncrono), sin depender de una entidad externa de confianza?
Realmente depende de lo que se pretenda hacer. Si la transacción trata con la persona que recibe ETH/Tokens, puede bloquear los tokens en el contrato hasta que la persona llame a la función en una segunda transacción. Si tiene que ver con transiciones de estado, intente optimizar el almacenamiento de su contrato. En general, es mejor hacer lo menos posible en Solidity, para minimizar el costo y maximizar la seguridad.