Construcciones Gitian reproducibles... pero no el mismo hash que bitcoincore.org

Bitcoincore.org y Bitcoin.org le permitirán descargar un tarball para bitcoin v0.20.1

cuando lo hacen

bitcoind: 4ec74161b2a90293926ae8e20a2efbe952bd23b53aeebf051e6a6285ace18271
bitcoin-0.20.1-x86_64-linux-gnu.tar.gz: 376194f06596ecfa40331167c39bc70c355f960280bd2a645fdbf18f66527397

También dicen:

reproducir un binario para usted mismo le proporcionará el más alto nivel de seguridad disponible actualmente

Entonces, parece que el método actual para hacer esto es la maniobra de "construcción gitana".

cuando lo hago

bitcoind: c5fb850ed9e6afa0af5653e743084912c9bd71fb233acfe2d72738fc319f2181
bitcoin-0.20.1-x86_64-linux-gnu.tar.gz: 277599356bd2df760832c6636797fe5ea5a5c28d929d53635b685f5ac1e4689b

Pasé por el proceso gitian con Ubuntu 20.04 y Debian 10 . Ambos produjeron el mismo incorrecto? tarball, 2 configuraciones diferentes/ 2 sistemas operativos, mismo tarball.

Mis dos archivos de afirmación se cargan aquí para Debian y Ubuntu. https://github.com/miketwenty1/images/tree/master/bad_asserts


Como plebeyo puedo pensar 1 de 2 cosas...

Algo está mal/apagado con algunos de mis paquetes/versiones/env/OS/configuración O, todos los verificadores están mintiendo y Bitcoin ha sido comprometido. Ayúdame a reducir las posibilidades.

Me gustaría realizar este ejercicio correctamente y reproducir los mismos archivos binarios... pero no estoy seguro de cuál es el mejor camino a seguir... ¿cuáles son los siguientes pasos para verificar la compilación para v0.20.1? Parece que no puedo reproducir el tarball anunciado en bitcoincore. org y bitcoin. org. Sin embargo, puedo hacer una compilación reproducible que me haga cuestionar muchas cosas.

Me encantaría que alguien pudiera pasar por su proceso desde cero y ver si puede producir los mismos tarballs que estas personas ven en este repositorio. https://github.com/bitcoin-core/gitian.sigs/blob/master/0.20.1-linux /*/ bitcoin-core-linux-0.20-build.assert's. Y comparte su proceso completo conmigo. Después de reproducirme, estaría feliz de hacer un tutorial actual sobre el método y actualizar los Documentos, que (enlaces a continuación) están fechados y rotos para casi todos los métodos.

NOTA: Si esta es de hecho la forma de facto de hacer compilaciones reproducibles actualmente... sería bueno tener documentación que sea precisa y actual. Entiendo que Ginx es algo en lo que se está trabajando... pero sería bueno tener un documento actual en el ínterin para las personas que quieran verificar las compilaciones. También estaría muy satisfecho si alguien señalara algo que me falta.

enlaces de referencia:
https://gitian.org/
https://github.com/bitcoin-core/docs/blob/master/gitian-building.md
https://github.com/bitcoin-core/docs/tree/ maestro/construcción gitana
https://github.com/devrandom/gitian-builder/blob/master/README.md
https://github.com/bitcoin/bitcoin/blob/master/contrib/gitian-build.py

problema de referencia de github
https://github.com/devrandom/gitian-builder/issues/235

FYI, informó el problema en github.com/bitcoin/bitcoin/issues/20389

Respuestas (2)

Hice una reconstrucción de 0.20.1 y obtuve los mismos resultados que tú. Esto indicaría que una dependencia de compilación se ha actualizado para producir resultados ligeramente diferentes a la versión que estaba en uso en el momento del lanzamiento. Las versiones de dependencia de compilación están ancladas a diferencia de las dependencias de software reales. IIRC, esto es común para las compilaciones gitian y el intento de reconstruir incluso versiones más antiguas dará como resultado discrepancias similares.

Hay trabajo en curso para pasar a un sistema de compilaciones reproducibles diferente llamado guix. Este sistema de compilación fijará las versiones de dependencia exactas, junto con la opción de compilar toda la cadena de herramientas desde cero. Esto debería permitir compilaciones totalmente reproducibles que se pueden replicar en cualquier momento.


Aquí hay una explicación más detallada de este desajuste en particular, copiado de mi respuesta en este número de GitHub .

Si observa los resultados de compilación de Gitian, verá un archivo llamado bitcoin-0.20.1-x86_64-linux-gnu-debug.tar.gz. Si descomprime este archivo, habrá *.dbgarchivos, por ejemplo, bitcoind.dbgy bitcoin-qt.dbg. Estos *.dbgarchivos contienen los datos de depuración de sus respectivos binarios, es decir, bitcoind.dbgcontienen datos de depuración de bitcoind.

Para asegurarse de usar el dbgarchivo correcto con el binario correcto, gcc incrusta una suma de verificación del dbgarchivo dentro del propio binario. Esto significa que bitcoindcontiene una suma de comprobación de bitcoind.dbg. Esto es para evitar intentar depurar bitcoindcon otro dbgarchivo. Por ejemplo, si intenta decirle a gdb que el bitcoin-qt.dbgarchivo contiene los símbolos de depuración para bitcoind, detectará que no los contiene y no intentará cargar los símbolos de depuración de bitcoin-qt.dbg.

Los símbolos de depuración se compilan inicialmente en el bitcoindbinario, pero más tarde, durante la compilación de Gitian, se eliminan y se colocan en el bitcoind.dbgarchivo. Sin embargo, debido a que se compilan bitcoindinicialmente, los símbolos de depuración tienen un efecto en la identificación de compilación que gcc incrusta en el binario. El ID de compilación es un hash del binario compilado, incluidos los datos de depuración.

Entonces, el resultado final es que el binario publicado contiene dos compromisos con los símbolos de depuración, pero en realidad no los contiene.

Puede leer más sobre estos archivos de depuración separados aquí: https://sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html

El quid de este problema es que los símbolos de depuración de las versiones recientes de Gitian difieren de los símbolos de depuración que se generaron para la versión original. Esto significa que tanto el ID de compilación como la suma de verificación del símbolo de depuración que encontramos dentro bitcoindson diferentes. Esto da como resultado que los bitcoindvalores hash sean diferentes (así como todos los demás binarios). Y, por supuesto, eso hace que los hashes del archivo tar sean diferentes.


Aquí está la diferencia de los binarios que genera diffoscope:

--- bitcoind
+++ /mnt/archive/bitcoin/bitcoin-binaries/0.20.1/bitcoin-0.20.1/bin/bitcoind
├── readelf --wide --notes {}
│ @@ -1,15 +1,15 @@
│  Displaying notes found in: .note.ABI-tag
│    Owner                Data size     Description
│    GNU                  0x00000010    NT_GNU_ABI_TAG (ABI version tag)        OS: Linux, ABI: 3.2.0
│  Displaying notes found in: .note.gnu.build-id
│    Owner                Data size     Description
│ -  GNU                  0x00000014    NT_GNU_BUILD_ID (unique build ID bitstring)     Build ID: 6b464617f7f91fd270ac86f43ef4a58eeeedff19
│ +  GNU                  0x00000014    NT_GNU_BUILD_ID (unique build ID bitstring)     Build ID: 3a439a31a5157ff7052ed310050df5643a02ea3f
│  Displaying notes found in: .note.stapsdt
│    Owner                Data size     Description
│    stapsdt              0x00000036    NT_STAPSDT (SystemTap probe descriptors)        Provider: libstdcxx
│      Name: throw
│      Location: 0x00000000006e550d, Base: 0x000000000086d140, Semaphore: 0x0000000000000000
│      Arguments: 8@%rdi 8@%rsi
├── readelf --wide --decompress --hex-dump=.gnu_debuglink {}
│ @@ -1,5 +1,5 @@
│  Hex dump of section '.gnu_debuglink':
│    0x00000000 62697463 6f696e64 2e646267 00000000 bitcoind.dbg....
│ -  0x00000010 b25ceebb                            .\..
│ +  0x00000010 114d519d                            .MQ.

Como puede ver, solo hay dos diferencias aquí, una en la ID de compilación y otra en la .gnu_debuglinksección. De la documentación que vinculé anteriormente, podemos ver que esta .gnu_debuglinksección tiene la primera línea es el nombre del archivo de depuración seguido de suficientes 0 bytes para completar un límite de 4 bytes. La segunda línea es la suma de comprobación CRC de 4 bytes. Y es esta suma de comprobación de CRC la que difiere.

Entonces, ¿por qué los símbolos de depuración difieren aquí? Nuevamente, el difoscopía puede ayudarnos un poco.

--- bitcoind.dbg
+++ /mnt/archive/bitcoin/bitcoin-binaries/0.20.1/bitcoin-0.20.1/bin/bitcoind.dbg
├── readelf --wide --notes {}
│ @@ -1,15 +1,15 @@
│  Displaying notes found in: .note.ABI-tag
│    Owner                Data size     Description
│    GNU                  0x00000010    NT_GNU_ABI_TAG (ABI version tag)        OS: Linux, ABI: 3.2.0
│  Displaying notes found in: .note.gnu.build-id
│    Owner                Data size     Description
│ -  GNU                  0x00000014    NT_GNU_BUILD_ID (unique build ID bitstring)     Build ID: 6b464617f7f91fd270ac86f43ef4a58eeeedff19
│ +  GNU                  0x00000014    NT_GNU_BUILD_ID (unique build ID bitstring)     Build ID: 3a439a31a5157ff7052ed310050df5643a02ea3f
│  Displaying notes found in: .note.stapsdt
│    Owner                Data size     Description
│    stapsdt              0x00000036    NT_STAPSDT (SystemTap probe descriptors)        Provider: libstdcxx
│      Name: throw
│      Location: 0x00000000006e550d, Base: 0x000000000086d140, Semaphore: 0x0000000000000000
│      Arguments: 8@%rdi 8@%rsi
├── readelf --wide --debug-dump=info {}
│┄ error from `readelf --wide --debug-dump=info {}`:
│┄ readelf: Error: /build/binutils/src/binutils-gdb/binutils/dwarf.c:1989: read LEB value is too large to store in destination variable
│┄ readelf: Error: /build/binutils/src/binutils-gdb/binutils/dwarf.c:1989: read LEB value is too large to store in destination variable
│┄ readelf: Error: /build/binutils/src/binutils-gdb/binutils/dwarf.c:1989: read LEB value is too large to store in destination variable
│┄ readelf: Error: /build/binutils/src/binutils-gdb/binutils/dwarf.c:1989: read LEB value is too large to store in destination variable
│┄ readelf: Error: /build/binutils/src/binutils-gdb/binutils/dwarf.c:1989: read LEB value is too large to store in destination variable
│ @@ -85052,36 +85052,36 @@
│      <29607>   DW_AT_decl_line   : 124
│      <29608>   DW_AT_decl_column : 16
│      <29609>   DW_AT_type        : <0x28761>
│      <2960d>   DW_AT_data_member_location: 12
│   <2><2960e>: Abbrev Number: 30 (DW_TAG_member)
│      <2960f>   DW_AT_name        : (indirect string, offset: 0x13aaf): __kind
│      <29613>   DW_AT_decl_file   : 108
│ -    <29614>   DW_AT_decl_line   : 148
│ +    <29614>   DW_AT_decl_line   : 128
│      <29615>   DW_AT_decl_column : 7
│      <29616>   DW_AT_type        : <0x287a6>
│      <2961a>   DW_AT_data_member_location: 16
│   <2><2961b>: Abbrev Number: 30 (DW_TAG_member)
│      <2961c>   DW_AT_name        : (indirect string, offset: 0x7a535): __spins
│      <29620>   DW_AT_decl_file   : 108
│ -    <29621>   DW_AT_decl_line   : 154
│ +    <29621>   DW_AT_decl_line   : 134
│      <29622>   DW_AT_decl_column : 3
│      <29623>   DW_AT_type        : <0x2879a>
│      <29627>   DW_AT_data_member_location: 20
...

Hay muchos más resultados que no he incluido porque son casi todos iguales.

Ahora bien, esto no es muy útil, pero podemos ver que para un montón de funciones, el número de línea de esa función difiere en 20 líneas.

Para obtener más información, usé dwarfdump. Esto es lo que dice para la nueva compilación de las dos funciones que muestro en difscope (las funciones son __kind y __spins).

0x0002960e:     DW_TAG_member
                  DW_AT_name    ("__kind")
                  DW_AT_decl_file       ("/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h")
                  DW_AT_decl_line       (148)
                  DW_AT_decl_column     (0x07)
                  DW_AT_type    (0x000287a6 "int")
                  DW_AT_data_member_location    (0x10)

0x0002961b:     DW_TAG_member
                  DW_AT_name    ("__spins")
                  DW_AT_decl_file       ("/usr/include/x86_64-linux-gnu/bits/thread-shared-types.h")
                  DW_AT_decl_line       (154)
                  DW_AT_decl_column     (0x03)
                  DW_AT_type    (0x0002879a "short int")
                  DW_AT_data_member_location    (0x14)

Como puede ver por el nombre de archivo dado, estas funciones provienen de las bibliotecas instaladas en el sistema. Estos parecen ser encabezados para la implementación de gcc de c ++ stdlib.


Entonces, lo que sucedió es que libstdc ++ se actualizó en Ubuntu. Independientemente de las actualizaciones que hayan ocurrido, se ha movido algún código en algunos archivos de encabezado que Bitcoin Core incluye en su uso de c ++ stdlib. A su vez, compilar con esos encabezados actualizados da como resultado diferentes símbolos de depuración porque las declaraciones de funciones se han movido en esos archivos de encabezado. Esto da como resultado que gcc calcule una ID de compilación diferente y una suma de verificación de CRC diferente para los símbolos de depuración. Esto finalmente da como resultado que los binarios finales sean ligeramente diferentes, lo que hace que los valores hash no coincidan.

Tengo curiosidad sobre la elección de guix sobre Nix. ¿Tiene un enlace a alguna discusión sobre irc, github, etc. sobre por qué se eligió guix?
@RaghavSood De github.com/bitcoin/bitcoin/pull/15277 : "Guix es un administrador de paquetes transaccionales muy parecido a Nix, pero a diferencia de Nix, se enfoca más en la capacidad de arranque y reproducibilidad que son atractivas para proyectos sensibles a la seguridad como bitcoin ." No creo que haya habido mucha discusión sobre guix vs nix, solo que guix es lo que alguien se ha esforzado en hacer, así que es lo que obtenemos.
Gracias por la informacion detallada. Si es interesante, tengo una salida cmp aquí comparando ambos archivos bitcoind. github.com/devrandom/gitian-builder/issues/235 Luke-jr déjame saber que los archivos que parecían estar en cuestión eran: .note.gnu.build-id .gnu_debuglink @AndrewChow crees que esto es una falla de diseño o funciona ¿Como era la intención?
Es un defecto de diseño del sistema gitian, pero el sistema gitian también funciona según lo previsto.

Siempre que la imagen del sistema operativo subyacente sea susceptible de cambios, no obtendrá un sistema de compilación reproducible que garantice la reproducibilidad durante un largo período de tiempo. Si el sistema operativo puede actualizar las cadenas de herramientas del compilador, las versiones de libc y cualquier herramienta que se use durante una compilación gitian, se esperan cambios en el resultado en el futuro. Dado que este es el caso dado que gitian está basado en ubuntu, y los parches aún se envían a versiones anteriores de ubuntu, esto es de esperarse después de un tiempo.