[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-deep-evm-2-modelo-memoria-stack-storage-calldata":3},{"article":4,"author":54},{"id":5,"category_id":6,"title":7,"slug":8,"excerpt":9,"content_md":10,"content_html":11,"locale":12,"author_id":13,"published":14,"published_at":15,"meta_title":7,"meta_description":16,"focus_keyword":17,"og_image":18,"canonical_url":18,"robots_meta":19,"created_at":15,"updated_at":15,"tags":20,"category_name":34,"related_articles":35},"d8000000-0000-0000-0000-000000000102","a0000000-0000-0000-0000-000000000082","Deep EVM #2: Modelo de Memoria — Stack, Memory, Storage y Calldata","deep-evm-2-modelo-memoria-stack-storage-calldata","Una inmersión profunda en las cuatro ubicaciones de datos de la EVM — stack, memory, storage y calldata — sus costes, comportamiento y la fórmula de expansión de memoria.","## Las cuatro ubicaciones de datos de la EVM\n\nLa EVM tiene cuatro ubicaciones distintas donde se pueden almacenar datos, cada una con características de coste y persistencia muy diferentes. Elegir la ubicación incorrecta puede convertir una operación de $0.50 en una de $50.\n\n### Stack\nEl stack es la ubicación más barata y más restringida. Tiene una profundidad máxima de 1024 elementos, y cada elemento es una palabra de 256 bits. Los opcodes PUSH, DUP y SWAP manipulan el stack directamente. El coste es de solo 3 gas por operación.\n\nEl stack es perfecto para valores temporales durante cálculos, pero no puedes acceder a elementos en posiciones arbitrarias — solo los 16 superiores son accesibles vía DUP y SWAP.\n\n### Memory (Memoria volátil)\nLa memoria es un arreglo de bytes expandible que existe solo durante la ejecución del call context actual. Se accede en fragmentos de 32 bytes usando MLOAD y MSTORE, o byte a byte con MSTORE8.\n\nEl coste de la memoria crece cuadráticamente: las primeras palabras son baratas, pero expandir la memoria a tamaños grandes se vuelve extremadamente costoso. La fórmula es:\n\n```\ncoste_memoria = (palabras_memoria² \u002F 512) + (3 * palabras_memoria)\n```\n\nPor ejemplo, los primeros 724 bytes cuestan solo gas lineal. Pero expandir a 10KB cuesta significativamente más debido al término cuadrático. Esta es la razón por la que nunca debes asignar grandes buffers de memoria en contratos.\n\n### Storage (Almacenamiento persistente)\nEl storage es la ubicación más cara — es donde los datos persisten entre transacciones. Cada contrato tiene su propio espacio de almacenamiento, un mapa clave-valor donde tanto claves como valores son de 256 bits.\n\n```\n\u002F\u002F Costes de storage (post EIP-2929 + EIP-3529):\n\u002F\u002F SLOAD frío:         2100 gas\n\u002F\u002F SLOAD caliente:      100 gas\n\u002F\u002F SSTORE (0 → no-cero, frío): 22100 gas\n\u002F\u002F SSTORE (no-cero → no-cero, caliente): 100 gas\n\u002F\u002F Reembolso por limpiar slot: 4800 gas\n```\n\nEl layout de storage en Solidity es determinista: las variables de estado se asignan secuencialmente a slots comenzando desde el slot 0. Variables más pequeñas que 256 bits se empaquetan en el mismo slot cuando es posible.\n\n### Calldata\nCalldata son los datos de entrada enviados con una transacción o llamada. Es de solo lectura e inmutable. Cuesta 16 gas por byte no cero y 4 gas por byte cero — significativamente más barato que la memoria para operaciones de lectura.\n\nEn Solidity, los parámetros marcados como `calldata` en funciones externas evitan copiar datos a memoria, ahorrando gas.\n\n## Empaquetamiento de variables de almacenamiento\n\nUna de las optimizaciones más importantes es el empaquetamiento de variables de storage. La EVM opera en palabras de 32 bytes, así que variables más pequeñas pueden compartir un slot:\n\n```solidity\n\u002F\u002F Malo: 3 slots (3 * SSTORE = caro)\ncontract Ineficiente {\n    uint256 a; \u002F\u002F slot 0 (32 bytes)\n    uint8 b;   \u002F\u002F slot 1 (1 byte, pero ocupa slot completo)\n    uint256 c; \u002F\u002F slot 2 (32 bytes)\n}\n\n\u002F\u002F Bueno: 2 slots\ncontract Eficiente {\n    uint256 a; \u002F\u002F slot 0\n    uint256 c; \u002F\u002F slot 1\n    uint8 b;   \u002F\u002F slot 1 (empaquetado con c? No - slot 2)\n}\n\n\u002F\u002F Mejor: empaquetamiento explícito\ncontract MejorAun {\n    uint128 a; \u002F\u002F slot 0, primera mitad\n    uint128 b; \u002F\u002F slot 0, segunda mitad\n    uint256 c; \u002F\u002F slot 1\n}\n```\n\n## El puntero de memoria libre\n\nSolidity mantiene un \"puntero de memoria libre\" en la posición 0x40. Este puntero rastrea dónde comienza la memoria no utilizada. Cada vez que Solidity necesita asignar memoria, lee el puntero, escribe los datos ahí, y avanza el puntero.\n\n```\n\u002F\u002F Leer el puntero de memoria libre en Yul:\nassembly {\n    let ptr := mload(0x40)\n    \u002F\u002F ptr ahora apunta al inicio de memoria libre\n    mstore(ptr, 42) \u002F\u002F Escribir el valor 42\n    mstore(0x40, add(ptr, 32)) \u002F\u002F Avanzar el puntero\n}\n```\n\nEntender este mecanismo es crucial para escribir Yul optimizado, donde gestionas la memoria manualmente.\n\n## Returndata y code\n\nAdemás de las cuatro ubicaciones principales, hay dos más:\n\n- **Returndata** — Los datos devueltos por la última llamada externa. Accesible vía RETURNDATASIZE y RETURNDATACOPY. Es temporal y se sobrescribe con cada llamada externa.\n- **Code** — El bytecode del contrato en ejecución. Accesible vía CODESIZE y CODECOPY. Es inmutable y se puede usar para almacenar datos constantes directamente en el bytecode.\n\n## Implicaciones prácticas\n\nLa elección de ubicación de datos tiene consecuencias masivas en coste:\n\n1. **Usa calldata para parámetros de funciones externas** — Es más barato que copiar a memory\n2. **Cachea lecturas de storage en variables locales** — Una lectura de storage fría cuesta 2100 gas; una lectura de stack cuesta 3 gas\n3. **Empaqueta variables de storage** — Reduce el número de slots y por tanto de operaciones SSTORE\n4. **Evita asignar memoria grande** — El coste cuadrático te penalizará\n5. **Usa eventos para datos que solo necesitan ser leídos off-chain** — Los logs son mucho más baratos que el storage\n\n## Conclusión\n\nLas cuatro ubicaciones de datos de la EVM — stack, memory, storage y calldata — cada una existe para un propósito específico con un perfil de coste diferente. Entender cuándo usar cada una es la diferencia entre un contrato eficiente y uno que desperdicia el dinero de los usuarios en gas innecesario.","\u003Ch2 id=\"las-cuatro-ubicaciones-de-datos-de-la-evm\">Las cuatro ubicaciones de datos de la EVM\u003C\u002Fh2>\n\u003Cp>La EVM tiene cuatro ubicaciones distintas donde se pueden almacenar datos, cada una con características de coste y persistencia muy diferentes. Elegir la ubicación incorrecta puede convertir una operación de $0.50 en una de $50.\u003C\u002Fp>\n\u003Ch3>Stack\u003C\u002Fh3>\n\u003Cp>El stack es la ubicación más barata y más restringida. Tiene una profundidad máxima de 1024 elementos, y cada elemento es una palabra de 256 bits. Los opcodes PUSH, DUP y SWAP manipulan el stack directamente. El coste es de solo 3 gas por operación.\u003C\u002Fp>\n\u003Cp>El stack es perfecto para valores temporales durante cálculos, pero no puedes acceder a elementos en posiciones arbitrarias — solo los 16 superiores son accesibles vía DUP y SWAP.\u003C\u002Fp>\n\u003Ch3>Memory (Memoria volátil)\u003C\u002Fh3>\n\u003Cp>La memoria es un arreglo de bytes expandible que existe solo durante la ejecución del call context actual. Se accede en fragmentos de 32 bytes usando MLOAD y MSTORE, o byte a byte con MSTORE8.\u003C\u002Fp>\n\u003Cp>El coste de la memoria crece cuadráticamente: las primeras palabras son baratas, pero expandir la memoria a tamaños grandes se vuelve extremadamente costoso. La fórmula es:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>coste_memoria = (palabras_memoria² \u002F 512) + (3 * palabras_memoria)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Por ejemplo, los primeros 724 bytes cuestan solo gas lineal. Pero expandir a 10KB cuesta significativamente más debido al término cuadrático. Esta es la razón por la que nunca debes asignar grandes buffers de memoria en contratos.\u003C\u002Fp>\n\u003Ch3>Storage (Almacenamiento persistente)\u003C\u002Fh3>\n\u003Cp>El storage es la ubicación más cara — es donde los datos persisten entre transacciones. Cada contrato tiene su propio espacio de almacenamiento, un mapa clave-valor donde tanto claves como valores son de 256 bits.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Costes de storage (post EIP-2929 + EIP-3529):\n\u002F\u002F SLOAD frío:         2100 gas\n\u002F\u002F SLOAD caliente:      100 gas\n\u002F\u002F SSTORE (0 → no-cero, frío): 22100 gas\n\u002F\u002F SSTORE (no-cero → no-cero, caliente): 100 gas\n\u002F\u002F Reembolso por limpiar slot: 4800 gas\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>El layout de storage en Solidity es determinista: las variables de estado se asignan secuencialmente a slots comenzando desde el slot 0. Variables más pequeñas que 256 bits se empaquetan en el mismo slot cuando es posible.\u003C\u002Fp>\n\u003Ch3>Calldata\u003C\u002Fh3>\n\u003Cp>Calldata son los datos de entrada enviados con una transacción o llamada. Es de solo lectura e inmutable. Cuesta 16 gas por byte no cero y 4 gas por byte cero — significativamente más barato que la memoria para operaciones de lectura.\u003C\u002Fp>\n\u003Cp>En Solidity, los parámetros marcados como \u003Ccode>calldata\u003C\u002Fcode> en funciones externas evitan copiar datos a memoria, ahorrando gas.\u003C\u002Fp>\n\u003Ch2 id=\"empaquetamiento-de-variables-de-almacenamiento\">Empaquetamiento de variables de almacenamiento\u003C\u002Fh2>\n\u003Cp>Una de las optimizaciones más importantes es el empaquetamiento de variables de storage. La EVM opera en palabras de 32 bytes, así que variables más pequeñas pueden compartir un slot:\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-solidity\">\u002F\u002F Malo: 3 slots (3 * SSTORE = caro)\ncontract Ineficiente {\n    uint256 a; \u002F\u002F slot 0 (32 bytes)\n    uint8 b;   \u002F\u002F slot 1 (1 byte, pero ocupa slot completo)\n    uint256 c; \u002F\u002F slot 2 (32 bytes)\n}\n\n\u002F\u002F Bueno: 2 slots\ncontract Eficiente {\n    uint256 a; \u002F\u002F slot 0\n    uint256 c; \u002F\u002F slot 1\n    uint8 b;   \u002F\u002F slot 1 (empaquetado con c? No - slot 2)\n}\n\n\u002F\u002F Mejor: empaquetamiento explícito\ncontract MejorAun {\n    uint128 a; \u002F\u002F slot 0, primera mitad\n    uint128 b; \u002F\u002F slot 0, segunda mitad\n    uint256 c; \u002F\u002F slot 1\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2 id=\"el-puntero-de-memoria-libre\">El puntero de memoria libre\u003C\u002Fh2>\n\u003Cp>Solidity mantiene un “puntero de memoria libre” en la posición 0x40. Este puntero rastrea dónde comienza la memoria no utilizada. Cada vez que Solidity necesita asignar memoria, lee el puntero, escribe los datos ahí, y avanza el puntero.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Leer el puntero de memoria libre en Yul:\nassembly {\n    let ptr := mload(0x40)\n    \u002F\u002F ptr ahora apunta al inicio de memoria libre\n    mstore(ptr, 42) \u002F\u002F Escribir el valor 42\n    mstore(0x40, add(ptr, 32)) \u002F\u002F Avanzar el puntero\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Entender este mecanismo es crucial para escribir Yul optimizado, donde gestionas la memoria manualmente.\u003C\u002Fp>\n\u003Ch2 id=\"returndata-y-code\">Returndata y code\u003C\u002Fh2>\n\u003Cp>Además de las cuatro ubicaciones principales, hay dos más:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Returndata\u003C\u002Fstrong> — Los datos devueltos por la última llamada externa. Accesible vía RETURNDATASIZE y RETURNDATACOPY. Es temporal y se sobrescribe con cada llamada externa.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Code\u003C\u002Fstrong> — El bytecode del contrato en ejecución. Accesible vía CODESIZE y CODECOPY. Es inmutable y se puede usar para almacenar datos constantes directamente en el bytecode.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2 id=\"implicaciones-pr-cticas\">Implicaciones prácticas\u003C\u002Fh2>\n\u003Cp>La elección de ubicación de datos tiene consecuencias masivas en coste:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Usa calldata para parámetros de funciones externas\u003C\u002Fstrong> — Es más barato que copiar a memory\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Cachea lecturas de storage en variables locales\u003C\u002Fstrong> — Una lectura de storage fría cuesta 2100 gas; una lectura de stack cuesta 3 gas\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Empaqueta variables de storage\u003C\u002Fstrong> — Reduce el número de slots y por tanto de operaciones SSTORE\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Evita asignar memoria grande\u003C\u002Fstrong> — El coste cuadrático te penalizará\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Usa eventos para datos que solo necesitan ser leídos off-chain\u003C\u002Fstrong> — Los logs son mucho más baratos que el storage\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch2 id=\"conclusi-n\">Conclusión\u003C\u002Fh2>\n\u003Cp>Las cuatro ubicaciones de datos de la EVM — stack, memory, storage y calldata — cada una existe para un propósito específico con un perfil de coste diferente. Entender cuándo usar cada una es la diferencia entre un contrato eficiente y uno que desperdicia el dinero de los usuarios en gas innecesario.\u003C\u002Fp>\n","es","b0000000-0000-0000-0000-000000000001",true,"2026-03-28T10:44:31.089917Z","Inmersión profunda en las cuatro ubicaciones de datos de la EVM: stack, memory, storage y calldata. Costes, comportamiento y fórmula de expansión.","EVM modelo memoria",null,"index, follow",[21,26,30],{"id":22,"name":23,"slug":24,"created_at":25},"c0000000-0000-0000-0000-000000000016","EVM","evm","2026-03-28T10:44:21.513630Z",{"id":27,"name":28,"slug":29,"created_at":25},"c0000000-0000-0000-0000-000000000020","Gas Optimization","gas-optimization",{"id":31,"name":32,"slug":33,"created_at":25},"c0000000-0000-0000-0000-000000000014","Solidity","solidity","Blockchain",[36,42,48],{"id":37,"title":38,"slug":39,"excerpt":40,"locale":12,"category_name":34,"published_at":41},"d0000000-0000-0000-0000-000000000614","La capa de interoperabilidad de Ethereum: Como 55+ L2s se convierten en una sola cadena","capa-interoperabilidad-ethereum-55-l2s-una-sola-cadena","Ethereum tiene 55+ rollups Layer 2, fragmentando la liquidez y la experiencia del usuario. La capa de interoperabilidad de Ethereum — combinando mensajeria cross-rollup, secuenciadores compartidos y based rollups — busca unificarlos en una red componible unica.","2026-03-28T10:44:45.451917Z",{"id":43,"title":44,"slug":45,"excerpt":46,"locale":12,"category_name":34,"published_at":47},"d0000000-0000-0000-0000-000000000613","Pruebas ZK mas alla de los rollups: Inferencia de IA verificable en Ethereum","pruebas-zk-mas-alla-rollups-inferencia-ia-verificable-ethereum","Las pruebas de conocimiento cero ya no son solo una herramienta de escalabilidad. En 2026, zkML permite la inferencia de IA verificable on-chain, los coprocesadores ZK mueven el calculo pesado off-chain con verificacion on-chain, y nuevos sistemas de prueba como SP1 y Jolt lo hacen practico.","2026-03-28T10:44:45.446211Z",{"id":49,"title":50,"slug":51,"excerpt":52,"locale":12,"category_name":34,"published_at":53},"d0000000-0000-0000-0000-000000000590","EIP-7702 en la practica: construir flujos de cuenta inteligente despues de Pectra","eip-7702-en-la-practica-construir-flujos-cuenta-inteligente-despues-pectra","EIP-7702 permite a cualquier EOA de Ethereum actuar temporalmente como contrato inteligente en una sola transaccion. Asi se implementan transacciones por lotes, patrocinio de gas y recuperacion social con la nueva primitiva de account abstraction.","2026-03-28T10:44:43.986612Z",{"id":13,"name":55,"slug":56,"bio":57,"photo_url":18,"linkedin":18,"role":58,"created_at":59,"updated_at":59},"Open Soft Team","open-soft-team","The engineering team at Open Soft, building premium software solutions from Bali, Indonesia.","Engineering Team","2026-03-28T08:31:22.226811Z"]