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?
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.
matthias_buehlmann
rareCondition == true
o 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.shane fontaine
usuallyCheapFunction
fluctuará sirareConidition == 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.matthias_buehlmann
shane fontaine