Ethereum: de historia a labs
Artículo 4 de 48
8%
completado al llegar aquí
Sistemas distribuidosNota de investigación14 min de lectura
Metropolis a Istanbul: Ethereum madura antes del Merge
Byzantium, Constantinople, Petersburg, Istanbul y Muir Glacier: qué EIPs activó cada fork, por qué se pospuso Constantinople y qué cambió para contratos.
Ruta Ethereum: 0/48
Prerequisitos recomendados
Si alguno de estos conceptos todavía está medio nebuloso, empieza por aquí. Te ahorra tropiezos y un par de cejas fruncidas.
El 15 de enero de 2019, a unas 32 horas de un hard fork programado, los desarrolladores de Ethereum decidieron posponerlo. Un cambio en el precio de SSTORE (escribir en storage) podía volver vulnerables a contratos que ya estaban desplegados y que nunca habían cambiado una línea. Ese episodio resume este capítulo: un fork cambia las reglas debajo de código que no se puede editar.
Entre 2017 y 2020, Ethereum activó cinco forks antes de empezar la transición a proof-of-stake. El registro oficial lista cada uno con su fecha, bloque y EIPs. [1]
De Byzantium a Muir Glacier por altura de bloque
Cómo leer esta figura
Línea de tiempo horizontal por número de bloque en la red principal. En el bloque 4,370,000, Byzantium, octubre de 2017: REVERT, STATICCALL y status en receipts. En el bloque 7,080,000, marcado en ocre, una caja dice no se activó: en enero de 2019 EIP-1283 abría reentrada y el fork se pospuso. En el bloque 7,280,000, Constantinople más Petersburg, febrero de 2019: CREATE2, desplazamientos de bits y EXTCODEHASH, sin EIP-1283. En el bloque 9,069,000, Istanbul, diciembre de 2019: CHAINID y calldata a 16 de gas por byte. En el bloque 9,200,000, Muir Glacier, enero de 2020: solo retrasa la bomba de dificultad.
Brújula de lectura
Actor, evidencia y estado
Actor
Clientes y operadoresCada cliente implementa los EIPs del fork; cada operador actualiza antes del bloque de activación.
Evidencia
Meta-EIP del forkUn documento por fork con su nombre, bloque de activación y lista exacta de EIPs.
Estado
Reglas de la EVMOpcodes nuevos, costos de gas y formato de receipts que cambian desde un bloque concreto.
Preguntas guía
- ¿Qué podía hacer un contrato después de Byzantium que antes no podía?
- ¿Cómo se calcula de antemano la dirección de un contrato creado con
CREATE2? - ¿Por qué abaratar
SSTOREpodía abrir una reentrada en contratos ya desplegados? - ¿Qué hizo Istanbul para que fuera más barato publicar datos en la cadena?
Conexiones dentro de la serie
- Antes: Frontier, Homestead y The DAO: la red aprendió con golpes cuenta la reentrada original y la protección contra replay.
- Después: Berlin, London y EIP-1559: gas deja de ser solo subasta sigue con el cambio de mercado de fees.
- Profundización: EVM: stack, memory, storage y calldata detalla los opcodes; Proxies y upgrades: cambiar el motor con el auto andando usa
CREATE2yDELEGATECALL.
Historia de Metropolis: un upgrade en dos entregas
"Metropolis" fue el nombre de una etapa que se entregó en dos forks. Byzantium es "Metropolis parte 1" y Constantinople, "Metropolis parte 2", según sus propias especificaciones.
Byzantium se activó en el bloque 4,370,000, el 16 de octubre de 2017, con nueve EIPs. [2] Además de los cambios de EVM que veremos en la siguiente sección, añadió precompilados (contratos nativos en direcciones fijas) para operar sobre la curva elíptica alt_bn128 y para exponenciación modular, la base criptográfica para verificar pruebas de conocimiento cero dentro de un contrato.
Byzantium también retrasó la bomba de dificultad y bajó la recompensa por bloque de 5 a 3 ETH. La bomba es un término de la fórmula de dificultad de proof-of-work que crece de forma exponencial cada 100,000 bloques. Su propósito era volver la minería cada vez más lenta para forzar la migración a proof-of-stake. El retraso vino acompañado de una recompensa menor para no aumentar la emisión; Constantinople repitió la fórmula y bajó la recompensa a 2 ETH. [3]
Muir Glacier, en el bloque 9,200,000 (enero de 2020), hizo una sola cosa: retrasar de nuevo la bomba 4,000,000 de bloques. Su motivación registra que los tiempos de bloque habían pasado de unos 13,1 a 14,3 segundos y que seguirían empeorando. [4]
Traza de ejecución: qué ve un contrato después de Byzantium
Antes de Byzantium, un contrato que quería abortar tenía dos caminos: quedarse sin gas o ejecutar una instrucción inválida. Ambos consumían todo el gas restante y no dejaban explicar el motivo. REVERT (EIP-140) detiene la ejecución, deshace los cambios de estado, devuelve un bloque de memoria con el motivo y no consume el gas que sobra. [5] Cuando un require falla en Solidity, el compilador ejecuta este mismo opcode (0xfd). [17]
El otro cambio que un backend nota a diario está en los receipts. Antes, el receipt guardaba una raíz de estado intermedia y no decía si la transacción había tenido éxito. EIP-658 la reemplazó por un campo status: 1 si la llamada de nivel superior tuvo éxito, 0 si falló. [6] Cuando tu código lee receipt.status, usa este EIP.
STATICCALL (EIP-214) permite llamar a otro contrato prohibiendo cualquier modificación de estado durante esa llamada y sus subllamadas. Con un objetivo de compilación Byzantium o posterior, Solidity usa este opcode para llamar funciones view de otros contratos. [16]
Constantinople, en el bloque 7,280,000 (28 de febrero de 2019), sumó desplazamientos de bits (SHL, SHR, SAR), EXTCODEHASH para leer el hash del código de otra cuenta y CREATE2. [7]
CREATE2 (EIP-1014) despliega un contrato en una dirección que depende del creador, de una sal elegida y del código de inicialización, no del nonce del creador. La dirección es keccak256(0xff ++ creador ++ sal ++ keccak256(init_code)), de la que se toman los últimos 20 bytes. Eso permite conocer y usar una dirección antes de desplegar nada en ella. [8]
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
/// Ilustrativo: calcula la dirección que obtendrá un contrato desplegado
/// con CREATE2 según la fórmula de EIP-1014.
library Create2Address {
function predict(address deployer, bytes32 salt, bytes memory initCode)
internal
pure
returns (address)
{
bytes32 h = keccak256(
abi.encodePacked(bytes1(0xff), deployer, salt, keccak256(initCode))
);
return address(uint160(uint256(h))); // últimos 20 bytes
}
}Invariante en peligro: EIP-1283 y el estipendio de 2300 de gas
Constantinople iba a incluir también EIP-1283, que cobraba SSTORE según el cambio neto del slot dentro de la transacción. Escribir dos veces el mismo slot pasaba a ser mucho más barato. La idea era razonable; el problema estaba en una suposición que muchos contratos hacían sin saberlo.
Cuando un contrato envía ether con transfer() o send() de Solidity, el receptor recibe solo un estipendio de 2300 de gas. Con los precios anteriores, eso no alcanzaba para escribir en storage, así que muchos desarrolladores lo trataban como una barrera contra la reentrada. Con EIP-1283, ciertas escrituras cabían en 2300 de gas y la barrera desaparecía.
La alerta de la fundación lo resume así: con EIP-1283 algunos contratos ya desplegados podían volverse vulnerables a reentrada, en particular los que usaban transfer() o send() seguido de una operación que cambia estado. ChainSecurity reportó el problema y los clientes publicaron versiones que no activaban el fork en el bloque 7,080,000. [10]
La salida fue un segundo meta-EIP, Petersburg, que se activa en el mismo bloque 7,280,000 y retira EIP-1283. La especificación establece que, si ambos forks caen en el mismo bloque, Petersburg tiene precedencia. [9]
Istanbul volvió a introducir la medición neta de SSTORE con EIP-2200, pero añadió una guarda: si el gas restante es menor o igual que el estipendio de 2300, SSTORE falla. Así se conservó la suposición de los contratos antiguos. [11]
Cuello de botella: Istanbul reprecia el estado y abarata los datos
Istanbul se activó en el bloque 9,069,000, el 8 de diciembre de 2019, con seis EIPs. [12] Dos de ellos atacan el mismo cuello de botella desde lados opuestos.
El estado de Ethereum había crecido, y leerlo era más caro para los nodos de lo que el gas reflejaba. EIP-1884 subió SLOAD de 200 a 800 de gas y BALANCE y EXTCODEHASH de 400 a 700. El propio EIP advierte que algunos contratos cuyas funciones por defecto leen storage podían dejar de caber en los 2300 de gas del estipendio. [13]
En sentido contrario, EIP-2028 bajó el costo de cada byte no nulo de calldata de 68 a 16 de gas. Publicar datos se volvió unas cuatro veces más barato, lo que favorece a sistemas de capa 2 que suben datos comprimidos a la cadena. [14]
Istanbul añadió además CHAINID (EIP-1344), que deja a un contrato leer el identificador de cadena. Es el complemento en la EVM de la protección contra replay del capítulo anterior: un contrato que verifica firmas puede incluir el chainId en el mensaje firmado. [15]
Riesgo operativo
Preparar un contrato desplegado para un hard fork
La lección para un equipo actual es que el código inmutable no vive en un entorno inmutable. Cualquier contrato que fije una cantidad de gas, o que confíe en que una operación "no cabe" en cierto presupuesto, depende de una tabla de precios que el protocolo puede cambiar.
Bibliografía académica
- [1]
ethereum.org, "Timeline of all Ethereum forks (2014 to present)."
Fechas, bloques y EIPs de Byzantium, Constantinople, Istanbul y Muir Glacier.
- [2]
A. Beregszaszi, "EIP-609: Hardfork Meta: Byzantium," Ethereum Improvement Proposals, no. 609, Apr. 2017.
Bloque 4,370,000 y los nueve EIPs de Byzantium.
- [3]
A. Schoedon and V. Buterin, "EIP-649: Metropolis Difficulty Bomb Delay and Block Reward Reduction," Ethereum Improvement Proposals, no. 649, Jun. 2017.
Retraso de la bomba de dificultad y recompensa base de 3 ETH.
- [4]
E. Conner, "EIP-2384: Muir Glacier Difficulty Bomb Delay," Ethereum Improvement Proposals, no. 2384, Nov. 2019.
Retraso de 4,000,000 de bloques y efecto observado de la bomba en los tiempos de bloque.
- [5]
A. Beregszaszi and N. Mushegian, "EIP-140: REVERT instruction," Ethereum Improvement Proposals, no. 140, Feb. 2017.
REVERT deshace cambios, devuelve datos y no consume el gas restante.
- [6]
N. Johnson, "EIP-658: Embedding transaction status code in receipts," Ethereum Improvement Proposals, no. 658, Jun. 2017.
Campo status en receipts: 1 éxito, 0 fallo.
- [7]
N. Savers, "EIP-1013: Hardfork Meta: Constantinople," Ethereum Improvement Proposals, no. 1013, Apr. 2018.
Bloque 7,280,000 y EIPs incluidos en Constantinople, entre ellos EIP-1283.
- [8]
V. Buterin, "EIP-1014: Skinny CREATE2," Ethereum Improvement Proposals, no. 1014, Apr. 2018.
Opcode CREATE2 y fórmula de la dirección resultante.
- [9]
A. Schoedon and M. van der Wijden, "EIP-1716: Hardfork Meta: Petersburg," Ethereum Improvement Proposals, no. 1716, Jan. 2019.
Retira EIP-1283 de Constantinople por un vector de reentrada; mismo bloque 7,280,000.
- [10]
H. Jameson, "Security Alert: Ethereum Constantinople Postponement," Ethereum Foundation Blog, Jan. 15, 2019.
Posposición del fork previsto en el bloque 7,080,000 por la reentrada habilitada por EIP-1283.
- [11]
W. Tang, "EIP-2200: Structured Definitions for Net Gas Metering," Ethereum Improvement Proposals, no. 2200, Jul. 2019.
Medición neta de SSTORE con la guarda del estipendio de 2300 de gas.
- [12]
A. Beregszaszi and A. Schoedon, "EIP-1679: Hardfork Meta: Istanbul," Ethereum Improvement Proposals, no. 1679, Jan. 2019.
Bloque 9,069,000 y los seis EIPs de Istanbul.
- [13]
M. H. Swende, "EIP-1884: Repricing for trie-size-dependent opcodes," Ethereum Improvement Proposals, no. 1884, Mar. 2019.
SLOAD 200 a 800, BALANCE y EXTCODEHASH 400 a 700; riesgo para funciones por defecto con 2300 de gas.
- [14]
A. Akhunov, E. Ben-Sasson, T. Brand, L. Guthmann, and A. Levy, "EIP-2028: Transaction data gas cost reduction," Ethereum Improvement Proposals, no. 2028, May 2019.
Calldata no nula de 68 a 16 de gas por byte.
- [15]
R. Meissner and B. Eisenbach, "EIP-1344: ChainID opcode," Ethereum Improvement Proposals, no. 1344, Aug. 2018.
Opcode CHAINID en 0x46.
- [16]
Solidity Team, "Contracts," Solidity documentation.
Las funciones view se llaman con STATICCALL desde el objetivo Byzantium.
- [17]
Solidity Team, "Expressions and Control Structures," Solidity documentation.
require y revert ejecutan la instrucción REVERT (0xfd).
Rutas vecinas
Si este tema te abrió hambre, sigue por aquí.
Series y labs que comparten área o dependen de esta ruta. Pocas opciones, para no convertir la curiosidad en menú infinito.
Series relacionadas
HotStuff: de cero a estado del arte
Ruta progresiva para entender consenso BFT moderno: quórums, sincronía parcial, locks, taxonomía one/two/three-chain, QC/highQC, multipipeline, view-change, responsiveness, AggQC, Fast-HotStuff, sync y frontera DAG-BFT.
Substrate: del runtime al consenso propio
Serie de 20 capítulos, de neófito a experto, sobre Substrate (Polkadot SDK): runtime en Wasm, FRAME, extrinsics, estado, pesos, actualizaciones sin fork, Aura, BABE, GRANDPA, sincronización, parachains, XCM, Sassafras, BEEFY y cómo conectar un consenso BFT propio a un nodo.
Ruta práctica: activos digitales en la operación
Nueve módulos, de menor a mayor dependencia, para decidir cómo usar custodia, wallets, llaves, firmas multifirma y MPC, AML/KYT y stablecoins con Fireblocks, BitGo, Kaleido, Circle y Tether.
Labs para convertir lectura en práctica
Prueba de trabajo y reajuste de dificultad
Laboratorio determinista para medir el costo de la prueba de trabajo y ver cómo el reajuste por altura de bloque estabiliza el tiempo entre bloques.
Consensus benchmark
Banco reproducible para comparar consenso BFT y documentar los trade-offs de HotStuff-2.
Ethereum local: Anvil, wallet y primera transacción
Laboratorio base para levantar una red local, crear cuentas, firmar transacciones y observar receipts sin gastar ETH real.
RPC y Cast: leer Ethereum con lupa
Ejercicios con JSON-RPC y Cast para consultar bloques, nonces, gas, receipts, logs y errores reproducibles.
Sigue leyendo
Ideas conectadas con este artículo
Una ruta corta para continuar sin abrir veinte pestañas y perder el hilo.
Frontier, Homestead y The DAO: la red aprendió con golpes
De mainnet inicial a The DAO: primeros forks, tensiones sociales y por qué la historia de Ethereum no es solo técnica.
Antes de Ethereum: Bitcoin, scripts y la máquina mundial
Historia inicial de Ethereum: qué problema vio el whitepaper, por qué los contratos generales importaban y qué cambió frente a Bitcoin.
Por qué Ethereum necesitaba The Merge
Motivos técnicos, económicos y ambientales detrás de la transición de proof-of-work a proof-of-stake.
EVM: stack, memory, storage y calldata
Modelo operativo de la Ethereum Virtual Machine: pila, memoria temporal, storage persistente, calldata y logs.