Compilación distinta e inconsistente de contrato heredado pero idéntico en solidez

Considere el siguiente archivo fuente de solidez A.sol:

pragma solidity ^0.4.8;

contract A {}

y B.sol:

pragma solidity ^0.4.8;

contract A {}

contract B is A {}

Usando la versión 0.4.8 de solc, el código producido para las dos versiones del contrato A no es idéntico:

$ solc --bin A.sol 

======= A =======
Binary: 
6060604052346000575b60358060166000396000f30060606040525b60005600a165627a7a723058201f05fd362367eb20b594d9537e2d735626b1fc0909c76826b94103a678da6cf10029
$ solc --bin B.sol 

======= A =======
Binary: 
6060604052346000575b60358060166000396000f30060606040525b60005600a165627a7a723058207dd14680c4efdd761b8db9a748045c916aff2f0a11c4ee7b82731d287045f0540029

======= B =======
Binary: 
6060604052346000575b60358060166000396000f30060606040525b60005600a165627a7a72305820942c33894954b0c78b1da86869a47c578755a698e26f671c5b4450476a3d56bc0029

Si escanea los bytes 5820en las compilaciones de A, verá que las dos versiones difieren justo después.

Esperaba que las compilaciones de solc fueran repetibles (eso parece importante para verificar que el código en la cadena de bloques es consistente con la fuente pública), y no entiendo por qué estas dos versiones de A deberían diferir. ¿Qué me estoy perdiendo?

¡Muchas gracias por cualquier idea!

Actualización: aquí estoy usando el contrato vacío como ejemplo, pero primero encontré compilaciones inconsistentes con un contrato menos trivial. No es solo una peculiaridad del contrato vacío.

Respuestas (1)

No tengo una respuesta completa, pero compartiré lo que descubrí. Usé Browser Solidity para compilar contratos y usé el desensamblador de Etherscan para ayudarme con el resultado.

Cuando compilé contract A {}en Browser Solidity, miré "Ensamblaje" (necesita "Alternar detalles"). Muestra:

.código
  PUSH 60 contrato A {\n}
// Algunas cosas...
  JUMPI contrato A {\n}
etiqueta 1 contrato A {\n}
  JUMPDEST contrato A {\n}
// Desempaquetar el contrato para la implementación...
  RETORNO contrato A {\n}
.datos
  0:
// Ahora tenemos el contrato desplegado aquí
    .código
      PUSH 60 contrato A {\n}
      PUSH 40 contrato A {\n}
      MSTORE contrato A {\n}
    etiqueta 1 contrato A {\n}
      JUMPDEST contrato A {\n}
      EMPUJAR [Etiqueta de error] contrato A {\n}
      contrato de SALTO A {\n}
    .datos
// Oh, nada más que mostrar aquí, pero ahí es donde se pone interesante para nosotros.

Luego tomé el contenido de "Runtime Bytecode" y lo pegué en el desensamblador.

Las líneas:

[17] PUSH6 0x627a7a723058
[18] SHA3 // Su código de operación es 0x20

Corresponde al xxxxx5820que usted identificó. Y adivina qué:

> web3.toUtf8("0x627a7a723058")
"bzzr0X"

Luego, lo que viene justo después de eso, en mi caso 81ef35e9ce2010474897d82da20c73d954e24c1e93fceaca1da5d1ed75650a26, 32 bytes que, si regresa a Solidity, son los mismos que en "Ubicación de metadatos".

Así que entiendo que el código del contrato no ha cambiado; sólo tiene su dirección Swarm. Y los verificadores de contratos necesitan abstraer esa parte.

Editar: acabo de encontrar esta codificación del hash de metadatos en el código de bytes

¡Gracias por toda la investigación! Esto parece consistente con el hilo de reddit que @BokkyPooBah señala en un comentario de la publicación original. Dejaré que esto se asiente por un tiempo en caso de que otros quieran opinar, pero creo que tú y BokkyPooBah básicamente han descubierto esto.