Creación de contratos en Ethereum: código inicial y dirección resultante

Una transacción de creación de contrato en Ethereum no tiene una dirección de destino ordinaria. Contiene código compilado del contrato y, cuando el despliegue se completa correctamente, el contrato tiene una dirección propia. Estas afirmaciones describen partes distintas de la creación: lo que especifica la transacción y lo que produce el despliegue.

La diferencia se entiende mejor al separar tres elementos: el campo de destino de la transacción, el código que interviene en la inicialización y el campo contractAddress del recibo. Este artículo explica su relación mediante un registro hipotético, sin necesidad de seguir un procedimiento de despliegue.

Por qué una transacción de creación no tiene un destino normal

En el objeto de transacción descrito por la documentación JSON-RPC de Ethereum, to identifica normalmente al destinatario. En una transacción de creación de contrato, ese campo contiene null. Aquí, null significa que el campo no contiene una dirección de destinatario ordinaria; null no es una dirección.

La documentación de despliegue de Ethereum describe la creación mediante una transacción que contiene código compilado del contrato sin especificar un destinatario. Esto permite interpretar la ausencia de destino en su contexto: la transacción corresponde a una creación, en lugar de una petición dirigida a un destinatario existente.

Conviene distinguir el concepto de su representación. Una explicación puede indicar que no se especifica un destinatario, mientras que el objeto devuelto mediante JSON-RPC representa el destino como to: null. Hay que leer ese campo según su función documentada. No hace falta sustituirlo mentalmente por la dirección que aparece tras una creación completada correctamente.

El código de inicialización y el código desplegado corresponden a etapas distintas

En esta explicación conceptual, init code, o código de inicialización, designa el código que interviene en la etapa de creación. El código desplegado es el código final del contrato almacenado tras su creación. Esta terminología es una deducción explicativa a partir del proceso documentado, no una especificación completa del contenido de creación.

Las premisas proceden de la documentación de contratos de Solidity: el constructor se ejecuta una vez al crear el contrato, permite ejecutar código de inicialización y, después de su ejecución, se almacena el código final del contrato. Solidity también excluye expresamente del código desplegado el código del constructor y las funciones internas que solo se llaman desde él.

Estos detalles permiten distinguir entre el código utilizado durante la creación y el código que queda desplegado. No justifican considerar que el constructor, por sí solo, constituye todo el init code, ni dar por hecho que el contenido compilado de la transacción sea simplemente una copia sin cambios del código final desplegado.

Imagina dos carpetas en un ejercicio de clase: una para el código de la etapa de creación y otra para el código final desplegado. Las etiquetas ayudan a ordenar la explicación. No muestran las instrucciones individuales, la estructura completa del contenido ni una comparación byte a byte de los resultados de un compilador concreto. A este nivel, lo relevante es la función diferente de cada etapa.

Dónde aparece la dirección del contrato resultante

Una vez desplegado, el contrato tiene una dirección de Ethereum. En el recibo documentado de la transacción, contractAddress indica la dirección del contrato creado cuando se trata de una creación; en caso contrario, el campo es null. Por tanto, el campo de destino y el de la dirección creada requieren lecturas distintas.

El campo hash de una transacción la identifica. Identificarla no demuestra, por sí solo, que la creación haya terminado correctamente ni proporciona la dirección del contrato resultante. El recibo aporta el campo que describe ese resultado de creación.

También importa el estado de ejecución. Para los recibos que utilizan status, la documentación define 1 como éxito y 0 como fallo. Esa misma documentación describe por separado los recibos históricos anteriores a Byzantium que utilizan root; la explicación de status se aplica aquí a los recibos que contienen ese campo.

Una transacción pendiente no tiene un recibo disponible. Por eso, no debe darse por hecho que el registro completado del ejemplo siguiente exista mientras la transacción siga pendiente. La ausencia de recibo, por sí sola, tampoco ofrece un diagnóstico completo de sus circunstancias. Estas definiciones de campos proceden de la documentación JSON-RPC de Ethereum.

Cómo leer un registro hipotético de creación

Supongamos que un ejemplo inventado para una clase contiene una transacción de creación y su recibo correspondiente. Establecemos como premisa que la creación se completó correctamente. Utilizamos las etiquetas Transacción T y Dirección C como marcadores: ninguna representa un hash o una dirección reales, y no se presupone ningún cálculo de direcciones.

  • Identificador de la transacción: Transacción T.
  • Destino de la transacción: to: null.
  • Datos de entrada de la transacción: código compilado de la etapa de creación, supuesto para este ejercicio.
  • Status del recibo correspondiente: 1, que significa éxito.
  • ContractAddress del recibo correspondiente: Dirección C.

La deducción respaldada por estas premisas es que el destino null resulta compatible con la dirección creada que figura en el recibo. Las premisas son la creación satisfactoria supuesta y los significados documentados de to, status y contractAddress. El destino describe el campo del destinatario de la transacción; Dirección C describe el resultado de creación en el recibo correspondiente.

La deducción se limita al supuesto planteado. No demuestra que una transacción cualquiera que se haya enviado haya terminado correctamente, ni especifica el valor de todos los campos del recibo tras una creación fallida. El ejemplo tampoco aporta código real con el que analizar el comportamiento del contrato hipotético.

Lista de comprobación para interpretar un registro de creación

Estas preguntas ayudan a estudiar un registro de transacción ya proporcionado. Su finalidad es ordenar la información necesaria para esta interpretación concreta:

  1. ¿Qué campo estás leyendo? Distingue el campo to de la transacción del campo contractAddress del recibo.
  2. ¿Qué muestra el destino? En el objeto documentado de una transacción de creación, lo esperado es null en lugar de una dirección de destinatario ordinaria.
  3. ¿De qué etapa del código se habla? Distingue la inicialización del código final desplegado, especialmente cuando se menciona el constructor.
  4. ¿Hay un recibo disponible? Las transacciones pendientes no tienen un recibo disponible.
  5. ¿Qué resultado está respaldado? Cuando aparece status, interpreta su valor de éxito o fallo junto con el campo de la dirección creada.
  6. ¿Qué supuestos siguen presentes? Mantén explícitos los marcadores hipotéticos, el éxito establecido como premisa y los detalles que faltan.

El objetivo es comprender la relación entre la transacción de creación, su etapa de inicialización y la dirección resultante. Las definiciones de estos campos no sustituyen un análisis del comportamiento del contrato ni permiten extender las conclusiones del ejercicio a registros con información diferente o incompleta.

Este artículo educativo se ha elaborado con asistencia de IA. El registro inventado es un ejercicio de interpretación.

Lectura relacionada: Cómo se verifica una transacción en Ethereum y qué demuestra.