DEV Community

Cover image for GAS optimization en Solidity ⚡9 Tips para ahorrar
Armando Zlatkowicz
Armando Zlatkowicz

Posted on

GAS optimization en Solidity ⚡9 Tips para ahorrar

Al ser Ethereum una red con costos variables por transacción, ¡ahorrar la mayor cantidad de gas posible se vuelve algo indispensable! Veamos como podemos ahorrarnos unas monedas:


Carpincho Ahorrador

¿Qué es el GAS y cuál es su costo?

El GAS el que precio que debemos pagar por hacer una transacción en la red. Ya que para realizar las transacciones en la blockchain, se utiliza poder de computo (proveniente de todos los nodos participantes) para que estas puedan llevarse a cabo.

No solo es un costo por transacción, sino que también es la recompensa para aquellos validadores que prestan su computo para que la que red siga funcionando.

Pero cuidado: el costo de las transacciones también depende del contrato al que estemos llamando. Por lo que reducir este costo al mínimo mientras programamos es algo fundamental. Veamos cuales son las técnicas mas eficientes para lograr esto.

1. Memory vs Calldata📂

El lugar donde almacenamos nuestras variables influye directamente en el GAS utilizado, ya que dependiendo de en donde se guarde el dato va a costar más o menos. Entre memory y calldata, lo más económico es calldata.

Esto es gracias a que con memory estamos asignando un lugar en memoria para escribir y luego leer el dato. En cambio, calldata es de solo lectura.

2. Storage declaration

Declarar variables en Solidity no tiene costo, este último solo se empieza a aplicar cuando las inicializamos. Esto significa que la mejor opción es declarar variables e inicializarlas posteriormente. Veamos un ejemplo:

uint256 x = 1000000000000000000;
// Costo de GAS elevado.
uint256 x;

// GAS optimizado.
function totalSupply(uint _supply) public {
  x = _supply;
}
Enter fullscreen mode Exit fullscreen mode

3. Packaging variables📦

Solidity nos da la posibilidad de especificar el tamaño que ocupará nuestra variable en cada stack. Siendo las de mayor tamaño las que más cuestan y más tamaño ocupan. Por lo qué, almacenar pequeños valores en un mismo stack puede ser una práctica prudente para optimizar los costos de escritura:

/* 256 es la capacidad máxima de almacenamiento de un stack. 
Siendo 256 un stack completo. */

uint256 bigVariable = 100000000000000000000000000000000000000000000000000;

/* Estableciendo pequeños valores podemos guardar muchas variables 
en un mismo stack. */

uint8 smallVariable;
uint8 smallVariable2;
Enter fullscreen mode Exit fullscreen mode

4. On-chain vs Off-chain⛓️

Si ya formas parte hace tiempo del ecosistema crypto, seguramente hayas escuchado sobre los oráculos, estos intermediarios para tomar información del mundo real (como el precio del dólar) y trasladarla a la web 3. Siguiendo la lógica de la blockchain, cada vez que consultamos un dato en la misma nos cuesta dinero, entonces: ¿Cómo hacen los oráculos para consultar información constantemente sin pagar?

Esto es gracias a que la información de los oráculos se encuentra Off-chain, es decir, no está en la blockchain como tal, sino que utilizan bases de datos tradicionales. Al tener la información fuera de la cadena, la consulta es gratis. La escritura de la información sí cuesta dinero, ya que se está escribiendo información en la blockchain, pero esta se realiza una única vez.

Por lo tanto, mantener la mayor cantidad de información posible fuera de la cadena es lo más económico, reservando los datos On-chain solo para la información que requiera perdurar en el tiempo y ser accesible.

5. Valores zero0️⃣

En algunos lenguajes de programación es común inicializar variables en 0, pero en Solidity tenemos que tener en cuenta el factor lectura y escritura. Como ya sabemos, la lectura no cuesta dinero, pero la escritura sí. El valor de las variables numéricas en Solidity es 0 por defecto. Por lo tanto, inicializar una variable en 0 no solo es inútil, sino costoso.

// Mucho GAS desperdiciado!
uint256 x = 0;

// GAS optimizado
uint256 x;
Enter fullscreen mode Exit fullscreen mode

6. ¡Usa los Bytes a tu favor!

Las variables de tipo bytes son las más optimizadas en Solidity. Esto gracias a que es un tipo de dato más fácil de leer para la EVM y con un tamaño fijo (van desde bytes1 hasta bytes32).

Intenta utilizar el tipo de dato bytes lo más posible, es más eficiente que un string, ¡mientras más puedas reducir su tamaño (siendo 1 el más barato y 32 el más caro), más GAS vas a ahorrar!

7. Herencia🌱

Al heredar un contrato, evitamos tener que reescribir variables, funciones, eventos, etc. Reutilizar todas estás funciones es de gran ayuda para evitar generar más GAS.

8. Funciones🔎

Tanto la visibilidad como los parámetros de una función pueden afectar su costo de ejecución. Debemos marcar las funciones como “external” lo más posible, ya que es la visibilidad más optimizada en cuanto a uso de GAS. Y también procura reducir la cantidad de parámetros a lo más mínimo posible.

Aunque no lo parezca, las funciones de tipo “payable” son más eficientes que aquellas que no tienen este índice💸. Pero, ¿Por qué pasa esto? Esto sucede gracias a qué al indicar la función como payable, el compilador no verifica a quién enviamos el Ether, reduciendo la cantidad de pasos que realiza para ejecutar la función.

9. Usar Assembly

Incorporado en Solidity y la EVM como tal, podemos utilizar un lenguaje de bajo nivel conocido como Assembly para optimizar al máximo nuestro código. Por acá te dejo un ejemplo:

contract EjemploAssembly {
    // Variables de estado
    uint256 public resultado;

    // Función que realiza la multiplicación y suma de manera más eficiente
    function calcular(uint256 a, uint256 b, uint256 c) public {
        // Código Assembly optimizado
        assembly {
            // Multiplicación: a * b
            let multiplicacion := mul(a, b)

            // Suma: multiplicacion + c
            let suma := add(multiplicacion, c)

            // Se almacena el resultado en la variable de estado
            sstore(result_slot, suma)
        }
    }

    // Definición de la variable de estado para almacenar el resultado
    bytes32 constant result_slot = keccak256("resultado");
}
Enter fullscreen mode Exit fullscreen mode

🛑¡Importante!: si bien Assembly nos ayuda a disminuir el uso de GAS, en algunos casos dificulta la legibilidad del código. Por lo tanto, ¡utilízalo con cuidado y solo en los momentos necesarios!

Conclusión

La optimización del uso del GAS en nuestros contratos es de vital importancia para el desarrollo sostenible de la red. Mientras más optimizados estén nuestros contratos, más fácil y económico será su ejecución, ya que no solo abaratamos costos de envío, sino que también de computo.

Si bien optimizar el GAS es muy importante, no se debe sacrificar funcionabilidad y mantenibilidad en el proceso. 🍁

Top comments (0)