Sistema de archivos interplanetarios: hash trivial (identidad), bloque DAG y buffers de protocolo

Recientemente, IPFS agregó soporte para un hash trivial (identidad) . En mi artículo hablaré sobre ello y mostraré cómo se puede usar.


Permítame recordarle: InterPlanetary File System es una nueva red descentralizada para compartir archivos (servidor HTTP, Content Delivery Network ). Comencé la historia al respecto en el artículo "Sistema de archivos interplanetarios IPFS" .

Por lo general, cuando se realiza el hash, pasando por una función hash, los datos se comprimen irreversiblemente y, como resultado, se obtiene un identificador corto. Este identificador le permite encontrar datos en la red y verificar su integridad.


Un hash trivial son los datos en sí. Los datos no cambian de ninguna manera y, en consecuencia, el tamaño del "hash" es igual al tamaño de los datos.


Un hash trivial realiza la misma función que Datos: URL . El identificador de contenido en este caso contiene los datos en sí en lugar de un hash. Esto le permite anidar bloques secundarios en el padre, haciéndolos disponibles inmediatamente después de recibir el padre. También puede incluir datos del sitio directamente en el registro DNS.


Por ejemplo, codifique la cadena de texto "Hello World" en el identificador del contenido (CID) con un hash trivial.
imagen


Estructura de identificación:


[ ][varint  CID][varint  ][varint ID ][varint  ][] 

Comencemos desde el final.


[hash]


El hash trivial en nuestro caso es la cadena en sí. Vamos a traducirlo a HEX .


 " " = 0x"D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180" 

Este es el HEX de esta cadena codificada utf-8 . Pero para que el navegador sepa con certeza que se trata de una línea utf-8, agréguela al principio: 0xEFBBBF . Este es un marcador de secuencia de bytes (BOM).


 0x"EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180" 

[longitud de hash varint]


Ahora podemos calcular la longitud del "hash". Cada dos caracteres HEX son un byte. En consecuencia, la cadena resultante tiene 22 bytes de longitud. En HEX, será 0x16 .


Agregue 0x16 al comienzo de la línea.


 0x"16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180" 

[identificación de hash varint]


Ahora necesitamos la identificación hash. El hash trivial o identidad en la tabla hash tiene el identificador 0x00 .


Agregue 0x00 al comienzo de la línea.


 0x"00 16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180" 

Esto ya es una parte del identificador de hash múltiple , puede transcodificar HEX a Base58 y el hash múltiple está listo. Pero ipfs no lo reconoce fuera del identificador de contenido (CID).


Sigamos adelante.


[tipo de contenido varint]


Ahora mire la tabla multicodec para obtener el tipo de contenido. En nuestro caso, se trata de datos sin procesar y el identificador es 0x55 respectivamente.


Agregue 0x55 al comienzo de la línea.


 0x"55 00 16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180" 

[versión varint del CID]


Codificamos el formato de la primera versión del identificador de contenido . Por lo tanto, agregue 0x01.


Agregue 0x01 al comienzo de la línea.


 0x"01 55 00 16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180" 

Y ya estamos en la línea de meta.


[prefijo base]


Indica qué opción de codificación de datos binarios a texto se utiliza.


HEX (F)


Podemos usar el término HEX directamente agregando el símbolo "F" al comienzo del prefijo base HEX


 F01550016EFBBBFD09FD180D0B8D0B2D0B5D18220D0BCD0B8D180 

Tenemos un identificador HEX para el contenido que contiene la línea utf-8: "Hola mundo"


Prueba: / ipfs / F01550016EFBBBFD09FD180D0B8D0B2D0B5D18220D0BCD0B8D180


Base58btc (z)


Base58btc será más corto por lo tanto


Traducimos nuestra cadena HEX a base58btc. Puedes usar el convertidor en línea .


 0x"01 55 00 16 EFBBBF D09F D180 D0B8 D0B2 D0B5 D182 20 D0BC D0B8 D180" = "3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P" (base58btc) 

Agregue el carácter de prefijo base base58btc "z" al comienzo de la línea


 z3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P 

Tenemos base58btc, un identificador de contenido que contiene una línea utf-8: "Hola mundo"


Prueba: / ipfs / z3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P


Bloque DAG


El texto es bueno, pero para codificar una página HTML necesitamos incrustar sus datos en el bloque de directorio DAG.


Aquí está nuestro HTML:


 <b><i><u> </u></i></b> 

De manera similar, de acuerdo con las instrucciones anteriores, obtenemos el identificador de contenido en base58btc para este texto:


 zeExnPvBXdTRwCBhfkJ1fHFDaXpdW4ghvQjfaCRHYxtQnd3H4w1MPbLczSqyCqVo 

Ahora escriba el archivo JSON:


 { "links": [{ "Cid": { "/": "zeExnPvBXdTRwCBhfkJ1fHFDaXpdW4ghvQjfaCRHYxtQnd3H4w1MPbLczSqyCqVo" }, "Name": "index.html" }], "data": "CAE=" } 

  1. Los "datos" indican el tipo de bloque DAG: el directorio.
  2. "enlaces" es una matriz de enlaces de archivos.
  3. "Nombre" es el nombre del archivo, respectivamente.
  4. "Cid" contiene el identificador de contenido

ipfs dag put -f"protobuf" convierta JSON en bloque DAG a través de IPFS.


Tengo un multihash: QmXXixn4rCzGguhxQPjXQ8Mr5rdqwZfJTKkeB6DfZLt8EZ


En esta etapa, recibimos un bloque en el que un directorio con un archivo inscrito en el bloque.


Luego, usando esta multicash, descargue el bloque terminado


 ipfs block get QmXXixn4rCzGguhxQPjXQ8Mr5rdqwZfJTKkeB6DfZLt8EZ > block.dag 

Traducimos el contenido de block.dag a HEX:


 0x"123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801" 

Añadir:


  1. Versión CID (0x01)
  2. Tipo de contenido DAG (0x70)
  3. hash trivial (0x00)
  4. tamaño de datos 69 bytes (0x45)

 0x"01 70 00 45 123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801" 

Convierte a Base58btc y agrega el prefijo "z"


 z6S3Z3W1zuRxio8AJC41jRTdyU9pZWnU6sNbvyGyypEdD8JVNdW42ZmGYWKWGbVDELLvJNWcMspaZMUPZKt7JQmhdyXCqq7j37GL 

Por lo tanto, obtuvimos un identificador de contenido con un directorio en el que la página html index.html con el texto "Hola Mundo".


Prueba: / ipfs / z6S3Z3W1zuRxio8AJC41jRTdyU9pZWnU6sNbvyGyypEdD8JVNdW42ZmGYWKWGbVDELLvJNWcMspaZMUPZKt7JQmhdyXCqqjj37gL


Además, este hash también se puede incrustar en otro bloque o grabar en el registro DNS dnslink. Entonces, en un bloque, puede caber en un sitio pequeño y simple.


Búfer de bloque y protocolo DAG


El bloque DAG también se puede ensamblar manualmente. Un bloque DAG son datos de Protocol Buffers . La capa superior es merkledag.proto que tiene unixfs.proto en Datos.


Tampones de protocolo


Cualquier protobuffer comienza con el identificador de campo varint. A menudo, un identificador ocupa un byte ya que su valor total es menor que 0x80. En nuestro caso, el primer byte es 0x12. Los 3 bits inferiores de este campo son de tipo. El resto es la ID especificada en el archivo proto.


Delimitado por longitud

Desciframos el identificador:


 0x12 & 0x07 = 2 (: Length-delimited) 0x12 >> 3 = 2 (ID: 2) 

Delimitado por longitud significa que a varint le sigue el tamaño del campo en bytes y su contenido directamente. Este tipo se usa tanto para varias estructuras anidadas como para datos sin procesar (cadena, bytes, mensajes incrustados, campos repetidos empaquetados). Lo que el archivo proto ya define en él.


Varint

Descifrar el identificador de otro tipo:


 0x18 & 0x07 = 0 (: Varint) 0x12 >> 3 = 3 (ID: 3) 

Varint significa que sigue inmediatamente el valor en varint. Este contenedor se usa para escribir muchos tipos de valores (int32, int64, uint32, uint64, sint32, sint64, bool, enum). Lo que también define el archivo proto.


Analizaremos block.dag que tradujimos a HEX arriba


Para analizar un bloque, puede usar un sitio que analizará automáticamente cualquier buffer de protocolo sin usar archivos proto.


 0x"123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801" 

Desmontamos el bloque y mapeamos los identificadores de los archivos proto.


merkledag.proto
 // An IPFS MerkleDAG Link message PBLink { // multihash of the target object optional bytes Hash = 1; // utf string name. should be unique per object optional string Name = 2; // cumulative size of target object optional uint64 Tsize = 3; } // An IPFS MerkleDAG Node message PBNode { // refs to other objects repeated PBLink Links = 2; // opaque user data optional bytes Data = 1; } 

unixfs.proto
 message Data { enum DataType { Raw = 0; Directory = 1; File = 2; Metadata = 3; Symlink = 4; HAMTShard = 5; } required DataType Type = 1; optional bytes Data = 2; optional uint64 filesize = 3; repeated uint64 blocksizes = 4; optional uint64 hashType = 5; optional uint64 fanout = 6; } 

 12 (: 2 (Length-delimited). ID: 2 (PBLink PBNode.Links (merkledag.proto))) 3F (: 63 ) 0A (: 2 (Length-delimited). ID: 1 (PBLink.Hash)) 2F (: 47 ) 01 55 00 2B (CIDv1 Raw Identity 43 ) EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E = "<b><i><u> </u></i></b>" 12 (: 2 (Length-delimited). ID: 2 (PBLink.Name)) 0A (: 10 ) 696E6465782E68746D6C = "index.html" 18 (: 0 (Varint). ID: 3 (PBLink.Size)) 00 (: 0) 0A (: 2 (Length-delimited). ID: 1 (PBNode.Data = Data (unixfs.proto))) 02 (: 2 ) 08 (: 0 (Varint). ID: 1 (Data.Type)) 01 (1 == Data.DataType.Directory) 

En consecuencia, un bloque con dos archivos se verá así:


 12 (: 2 (Length-delimited). ID: 2 (PBLink PBNode.Links (merkledag.proto))) 3B (: 59 ) 0A (: 2 (Length-delimited). ID: 1 (PBLink.Hash)) 2F (: 47 ) 01 55 00 2B (CIDv1 Raw Identity 43 ) EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E = "<b><i><u> </u></i></b>" 12 (: 2 (Length-delimited). ID: 2 (PBLink.Name)) 06 (: 6 ) 312E68746D6C = "1.html" 18 (: 0 (Varint). ID: 3 (PBLink.Size)) 00 (: 0) 12 (: 2 (Length-delimited). ID: 2 (PBLink PBNode.Links)) 3B (: 59 ) 0A (: 2 (Length-delimited). ID: 1 (PBLink.Hash)) 2F (: 47 ) 01 55 00 2B (CIDv1 Raw Identity 43 ) EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E = "<b><i><u> </u></i></b>" 12 (: 2 (Length-delimited). ID: 2 (PBLink.Name)) 06 (: 6 ) 322E68746D6C = "2.html" 18 (: 0 (Varint). ID: 3 (PBLink.Size)) 00 (: 0) 0A (: 2 (Length-delimited). ID: 1 (PBNode.Data = Data(unixfs.proto))) 02 (: 2 ) 08 (: 0 (Varint). ID: 1 (Data.Type)) 01 (1 == Data.DataType.Directory) 

Es decir, el campo PBNode.Links (0x12) se repite tantas veces como el número de archivos que se colocarán en el bloque.


Para verificar, agregue al principio de "F 01 70 00" (Identidad HAG CIDv1 DAG) y el tamaño del bloque DAG "7E" (126 bytes)


 F 01 70 00 7E 12 3B 0A 2F 01 55 00 2B EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E 12 06 312E68746D6C 18 00 12 3B 0A 2F 01 55 00 2B EFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E 12 06 322E68746D6C 18 00 0A 02 08 01 

Compruebe: / ipfs / F0170007E123B0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E1206312E68746D6C1800123B0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E1206322E68746D6C18000A020801


Conclusión


Espero haber proporcionado suficiente información para que sea posible implementar la creación de bloques e identificadores.

Source: https://habr.com/ru/post/es423073/


All Articles