Ir al contenido principal
BlockchainMar 28, 2026

Deep EVM #3: Entendiendo el Gas — Por Qué Tu Contrato Cuesta Lo Que Cuesta

OS
Open Soft Team

Engineering Team

El gas como recurso computacional

El gas en Ethereum no es una tarifa arbitraria — es un sistema de precios preciso para los recursos computacionales. Cada opcode tiene un coste asignado que refleja el trabajo real del hardware: CPU para cálculos, I/O de disco para acceso a almacenamiento, ancho de banda de red para propagación de datos.

Entender el gas a nivel granular separa a los desarrolladores casuales de los optimizadores serios. En mercados competitivos como MEV, cada unidad de gas es margen de beneficio.

Gas intrínseco de transacción

Antes de que cualquier opcode se ejecute, la transacción ya ha consumido gas:

  • 21,000 gas — Coste base de cada transacción
  • 16 gas por byte de calldata no cero
  • 4 gas por byte de calldata cero
  • 32,000 gas adicional si la transacción crea un contrato (CREATE)

Esto significa que una simple transferencia de ETH cuesta exactamente 21,000 gas. Una llamada a función con un selector de 4 bytes y un parámetro address (20 bytes, mayormente no cero) cuesta aproximadamente 21,000 + (4 * 16) + (12 * 4) + (20 * 16) = 21,432 gas solo en gas intrínseco.

El sistema de niveles de gas

Los opcodes se agrupan en niveles de coste:

NivelCosteOpcodes representativos
Cero0 gasSTOP, RETURN, REVERT
Base2 gasADDRESS, CALLER, CALLVALUE
Muy bajo3 gasADD, SUB, LT, GT, AND, OR, XOR
Bajo5 gasMUL, DIV, MOD
Medio8 gasADDMOD, MULMOD, JUMP
Alto10 gasJUMPI

Los opcodes de acceso a estado son donde se concentra el coste real.

EIP-2929: Acceso frío y caliente

Antes de EIP-2929, cada SLOAD costaba 800 gas sin importar cuántas veces leyeras el mismo slot. EIP-2929 cambió esto introduciendo el concepto de “temperatura” de acceso:

  • La primera lectura de un slot es “fría” — 2100 gas
  • Las lecturas posteriores del mismo slot son “calientes” — 100 gas
  • Lo mismo aplica para direcciones externas: BALANCE, EXTCODESIZE, etc.

Esto creó un incentivo poderoso para cachear lecturas de storage en variables de memoria:

// Antes de EIP-2929, esto no importaba tanto:
function gastoInnecesario(uint256[] calldata ids) external {
    for (uint i = 0; i < ids.length; i++) {
        // Cada iteración lee totalSupply de storage
        require(balances[ids[i]] <= totalSupply);
    }
}

// Post EIP-2929, esto ahorra significativamente:
function gasOptimizado(uint256[] calldata ids) external {
    uint256 _totalSupply = totalSupply; // Frío una vez: 2100 gas
    for (uint i = 0; i < ids.length; i++) {
        // Usa variable de stack: 3 gas cada vez
        require(balances[ids[i]] <= _totalSupply);
    }
}

Listas de acceso (EIP-2930)

EIP-2930 permite declarar de antemano qué direcciones y slots de storage accederás. Esto “pre-calienta” esos accesos, pagando un coste reducido por adelantado:

  • 2400 gas por dirección en la lista de acceso
  • 1900 gas por slot de storage en la lista

Comparado con 2600 gas para una dirección fría o 2100 para un slot frío, las listas de acceso ofrecen un descuento modesto cuando sabes de antemano qué vas a acceder.

Mecánicas de reembolso

Históricamente, limpiar un slot de storage (ponerlo a cero) daba un reembolso de gas. Post EIP-3529 (London), el reembolso máximo está limitado al 20% del gas total usado:

  • SSTORE: establecer un slot no-cero de vuelta a cero reembolsa 4800 gas
  • SELFDESTRUCT: eliminado como fuente de reembolso

Esto mató los tokens de gas (CHI, GST2) que explotaban los reembolsos para obtener beneficio.

Patrones de optimización comprobados

1. Empaquetamiento de storage

Agrupar variables que se leen juntas en el mismo slot de 32 bytes reduce operaciones SLOAD.

2. Errores personalizados vs cadenas de revert

// Caro: almacena la cadena en el bytecode
require(balance >= amount, "Saldo insuficiente");

// Barato: solo el selector de 4 bytes
error SaldoInsuficiente();
if (balance < amount) revert SaldoInsuficiente();

3. Unchecked blocks para aritmética segura conocida

// Cuando sabemos que no habrá overflow:
unchecked {
    for (uint256 i = 0; i < length; ++i) {
        // Ahorra ~80 gas por iteración
    }
}

4. Calldata vs memory

Usar calldata para parámetros de funciones externas evita la copia a memoria.

5. Eventos vs storage para datos off-chain

Emitir un evento cuesta ~375 gas por topic + 8 gas por byte de datos. Mucho más barato que escribir al storage.

Conclusión

El gas no es un impuesto — es un sistema de precios que refleja el coste real de la computación y el almacenamiento. Entender los costes a nivel de opcode, las mecánicas frío/caliente de EIP-2929, y los patrones de optimización es esencial para construir contratos eficientes y competitivos.