¿Bandera de reentrada sin SSTORE?

¿Es posible crear un mutex que evite la reentrada sin usar la operación SSTORE?

Me gustaría crear una bandera para evitar el reingreso de mi contrato que llamará a otros contratos. La SSTOREoperación de escribir en el almacenamiento es costosa. ¿Hay alguna manera de mantener este mutex en la memoria o hacerlo con operaciones menos costosas?

Estoy escribiendo con Solidity, pero tengo curiosidad por cualquier versión. Parece que este problema existirá para casos de uso más allá de la protección de reingreso. Limitar las tarifas manteniéndolas solo Gsresetdespués de la inicialización es lo más barato que puedo pensar en este momento, pero tal vez hay algo que me estoy perdiendo.

Respuestas (2)

¿Hay alguna manera de mantener este mutex en la memoria?

La memoria y la pila en EVM están aisladas para las llamadas de mensajes anidados, lo que significa que no hay forma de acceder a un conjunto de mutex de memoria en la llamada/transacción externa.

hacerlo con operaciones menos costosas?

La única forma que se me ocurre es usar el almacenamiento ya que, a diferencia de la memoria y la pila, el almacenamiento se comparte para el mismo contrato en diferentes llamadas de mensajes. Tenga en cuenta que al restablecer la bandera de exclusión mutua, el almacenamiento se restablece, lo que significa que se reembolsará parte del combustible. En el papel amarillo Gsclear = 15000 se define:

Reembolso otorgado (agregado al contador de reembolso) cuando el valor de almacenamiento se establece en cero desde un valor distinto de cero.

Así que en el mejor de los casos solo tendrías que pagar Gsset - Gsclear = 5000gasolina. Dije "en el mejor de los casos" porque el reembolso tiene un tope máximo de la mitad (redondeado hacia abajo) del monto total utilizado, como se especifica en la sección 6.2. El límite será de al menos 10000 ya que siempre debe configurar primero el mutex, que cuesta 20000. Entonces, en el peor de los casos, pagaría 10000 de gasolina.

En mi humilde opinión, es inevitable usar almacenamiento, por lo tanto, el SSTOREcódigo de operación :( Tomemos este contrato simple como ejemplo. Utiliza mutexes para evitar el reingreso en la withdrawBalance()función.

pragma solidity ^0.4.16;

contract EtherBank{
    mapping(address => uint) public userBalances;
    mapping(address => bool) public withdrawMutex;

    function getBalance(address user) constant returns(uint) {  
        return userBalances[user];
    }

    function addToBalance() {  
        userBalances[msg.sender] += msg.value;
    }

    function withdrawBalance() {  
        if ( withdrawMutex[msg.sender] == true) { throw; }
        withdrawMutex[msg.sender] = true;
        uint amountToWithdraw = userBalances[msg.sender];
        if (amountToWithdraw > 0) {
            if (!(msg.sender.send(amountToWithdraw))) { throw; }
         }
        userBalances[msg.sender] = 0;
        withdrawMutex[msg.sender] = false;
    }
}

Este es un contrato bancario simple tomado de este blog , cuya lectura es muy recomendable si está interesado en los errores de reingreso en los contratos inteligentes. Como muestra este ejemplo, withdrawMutexse almacena en el almacenamiento permanente del contrato.

Simplemente no puede tener su mutex almacenado en la memoria, porque se eliminaría después de cada invocación del contrato. El mutex debe mantener su estado posiblemente para muchas invocaciones del contrato, lo que implica que debe almacenarse en el almacenamiento permanente. Malas noticias para el uso de gas :(

Sin embargo, podría evitar errores de reingreso utilizando diferentes estrategias, como la mencionada en la publicación del blog. Esta táctica simple es mucho más amigable con el costo de la gasolina:

function withdrawBalance() {  
        uint amountToWithdraw = userBalances[msg.sender];
        userBalances[msg.sender] = 0;
        if (amountToWithdraw > 0) {
        if (!(msg.sender.send(amountToWithdraw))) { throw; }
    }

¡Así que solo haga su pedido correcto! ;)