¿Qué hace el código de bytes del contrato en blanco?

Cuando compilo un contrato en blanco:

contract A {}

con

solc --optimize --optimize-runs 300000 --opcodes test.sol

Yo obtengo:

PUSH1 0x60 PUSH1 0x40 MSTORE PUSH1 0x6 DUP1 PUSH1 0x10 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN PUSH1 0x60 PUSH1 0x40 MSTORE STOP

¿Qué es? Según tengo entendido, este código de bytes no es el código del contrato, sino el código que durante la ejecución genera el contrato. Pero no entiendo lo que está pasando.

Probablemente

PUSH1 0x60 PUSH1 0x40 MSTORE

es un patrón para asignar 64 bytes (0x40) en la memoria. En caso afirmativo, ¿por qué necesitamos asignarlo manualmente?

Hay algunas líneas en papel amarillo sobre la separación de 'código' y 'datos'. Puedo verlo, cuando se ejecuta solccon --asm-json. Pero, ¿cómo interactúan realmente estas dos partes?

Siento que me perdí un papel o manual muy importante donde se aclara todo. ¿Dónde puedo conseguirlo?

Para resumir:

  1. ¿Qué hace el código de bytes del contrato en blanco? Si es posible, necesito una explicación para cada código de operación.
  2. ¿Cómo interactúan codey las datasecciones del contrato?
  3. ¿Dónde puedo encontrar información completa sobre cómo funciona evm?
¡Bienvenido a Ethereum Stack Exchange! La primera pregunta es brillante. Sin embargo, se prefiere si puede publicar preguntas separadas en lugar de combinarlas en una sola. De esa manera , ayuda a las personas que responden a su pregunta y también a otras que buscan al menos una de sus preguntas. ¡Gracias!

Respuestas (2)

La sección de "datos" mencionada en el papel amarillo es la parte que sigue a la instrucción PUSH, es decir, el papel amarillo solo habla de datos de inserción. Lo que ve en la salida del ensamblaje es un concepto de nivel superior.

El (código de inicio del) contrato en blanco copia el código de contrato final del código a la memoria y luego lo devuelve.

Tanto el código de contrato final como el código de inicio comienzan almacenando el llamado "puntero de memoria libre" en la posición de memoria 0x40. Este puntero le indica dónde se puede asignar el siguiente fragmento de memoria libre. En el caso de este contrato, esto es totalmente innecesario y probablemente se optimizará en la siguiente fase de mejora del optimizador.

Un usuario de Reddit publicó amablemente un análisis de código de operación por código de operación para usted:

PUSH1 0x60 PUSH1 0x40 MSTORE

Almacene 0x60 en la ubicación de memoria 0x40. Creo que esto se usa normalmente para la indexación de variables si tiene una. Nunca he entrado en detalles de esto.

PUSH1 0x6 DUP1

Inserte 2 valores de 0x6 en la pila. Uno se debe usar como parámetro para CODECOPY, el otro se debe usar como parámetro para RETURN. Este es el tamaño del cuerpo de su código. Consiste en PUSH1 0x60 PUSH1 0x40 MSTORE (nuevamente indexación variable) STOP (se explica por sí mismo).

EMPUJAR 0x10

Este es un parámetro de CODECOPY. Se refiere al desplazamiento donde se encuentra el código que se va a copiar en la memoria. Básicamente, el cuerpo de su código (la parte no constructora).

EMPUJAR1 0x0

Parámetro de CODECOPIA. Se refiere a qué memoria compensa el código que se va a copiar.

CODECOPIA

Copie parte del código en la memoria. Según el parámetro que le hemos dado, solicita copiar 6 bytes desde el desplazamiento del byte 17 (si cuenta desde 1) en la ubicación de memoria 0.

EMPUJAR 0x0 VOLVER

RETURN toma dos parámetros, el número de bytes a devolver y el desplazamiento en memoria a devolver. Dado que estamos creando un contrato, este es el código que pretendemos cargar. Así que tenemos 6 bytes (del DUP1 anterior), que es el tamaño y 0 (compensación de memoria en la que copiamos el código anterior).