Sistema de arquivos interplanetário - hash (identidade) trivial, bloco DAG e buffers de protocolo

Recentemente, o IPFS adicionou suporte para um hash trivial (identidade) . No meu artigo, vou falar sobre isso e mostrar como ele pode ser usado.


Deixe-me lembrá-lo: O InterPlanetary File System é uma nova rede descentralizada de compartilhamento de arquivos (servidor HTTP, rede de entrega de conteúdo ). Comecei a história sobre isso no artigo "Sistema de arquivos interplanetário IPFS" .

Geralmente, ao fazer o hash, passando por uma função de hash, os dados são irreversivelmente "compactados" e, como resultado, um pequeno identificador é obtido. Esse identificador permite encontrar dados na rede e verificar sua integridade.


Um hash trivial são os próprios dados. Os dados não mudam de forma alguma e, portanto, o tamanho do "hash" é igual ao tamanho dos dados.


Um hash trivial executa a mesma função que Data: URL . O identificador de conteúdo nesse caso contém os próprios dados em vez de um hash. Isso permite aninhar blocos filhos no pai, disponibilizando-os imediatamente após o recebimento do pai. Você também pode incluir dados do site diretamente no registro DNS.


Por exemplo, codifique a sequência de texto "Hello World" no identificador do conteúdo (CID) com um hash trivial.
imagem


Estrutura de identificação:


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

Vamos começar do fim.


[hash]


O hash trivial no nosso caso é a própria string. Vamos traduzi-lo para HEX .


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

Este é o HEX dessa sequência codificada utf-8 . Mas, para que o navegador tenha certeza de que essa é uma linha utf-8, adicione-a no começo: 0xEFBBBF . Este é um marcador de sequência de bytes (BOM).


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

[comprimento do hash varint]


Agora podemos calcular o comprimento do "hash". Cada dois caracteres HEX são um byte. Por conseguinte, a cadeia resultante tem 22 bytes. No HEX, será 0x16 .


Adicione 0x16 ao início da linha.


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

[varint hash id]


Agora precisamos do hash id. O hash ou identidade trivial na tabela de hash tem o identificador 0x00 .


Adicione 0x00 ao início da linha.


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

Esta já é uma parte com múltiplos hash do identificador, você pode transcodificar HEX para Base58 e o multi-hash está pronto. Mas o ipfs não o reconhece fora do identificador de conteúdo (CID).


Vamos seguir em frente.


[tipo de conteúdo varint]


Agora observe a tabela multicodec para obter o tipo de conteúdo. No nosso caso, são dados brutos e o identificador é 0x55 respectivamente.


Adicione 0x55 ao início da linha.


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

[versão varint do CID]


Codificamos o formato da primeira versão do identificador de conteúdo . Portanto, adicione 0x01.


Adicione 0x01 ao início da linha.


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

E assim já estamos na linha de chegada.


[prefixo base]


Indica qual opção de codificação de dados binários para texto é usada.


HEX (F)


Podemos usar o termo HEX diretamente adicionando o símbolo "F" no início do prefixo base HEX


 F01550016EFBBBFD09FD180D0B8D0B2D0B5D18220D0BCD0B8D180 

Temos um identificador HEX para o conteúdo que contém a linha utf-8: "Hello world"


Teste: / ipfs / F01550016EFBBBFD09FD180D0B8D0B2D0B5D18220D0BCD0B8D180


Base58btc (z)


Base58btc será mais curto, portanto


Traduzimos nossa string HEX para base58btc. Você pode usar o conversor online .


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

Adicione o caractere de prefixo base base58btc "z" ao início da linha


 z3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P 

Temos o base58btc, um identificador de conteúdo que contém uma linha utf-8: "Hello world"


Teste: / ipfs / z3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P


Bloco DAG


O texto é bom, mas para codificar uma página HTML, precisamos incorporar seus dados no bloco de diretório do DAG.


Aqui está o nosso HTML:


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

Da mesma forma, de acordo com as instruções acima, obtemos o identificador de conteúdo em base58btc para este texto:


 zeExnPvBXdTRwCBhfkJ1fHFDaXpdW4ghvQjfaCRHYxtQnd3H4w1MPbLczSqyCqVo 

Agora escreva o arquivo JSON:


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

  1. Os "dados" indicam o tipo de bloco DAG - o diretório.
  2. "links" é uma matriz de links de arquivos.
  3. "Nome" é o nome do arquivo, respectivamente.
  4. "Cid" contém o identificador de conteúdo

ipfs dag put -f"protobuf" converta JSON em bloco DAG via IPFS.


Eu tenho um multihash: QmXXixn4rCzGguhxQPjXQ8Mr5rdqwZfJTKkeB6DfZLt8EZ


Nesse estágio, recebemos um bloco no qual um diretório com um arquivo inscrito no bloco.


Em seguida, usando essa multicash, descarregue o bloco concluído


 ipfs block get QmXXixn4rCzGguhxQPjXQ8Mr5rdqwZfJTKkeB6DfZLt8EZ > block.dag 

Traduzimos o conteúdo de block.dag para HEX:


 0x"123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801" 

Adicionar:


  1. Versão CID (0x01)
  2. Tipo de conteúdo DAG (0x70)
  3. hash trivial (0x00)
  4. tamanho dos dados 69 bytes (0x45)

 0x"01 70 00 45 123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801" 

Converta em Base58btc e adicione o prefixo "z"


 z6S3Z3W1zuRxio8AJC41jRTdyU9pZWnU6sNbvyGyypEdD8JVNdW42ZmGYWKWGbVDELLvJNWcMspaZMUPZKt7JQmhdyXCqq7j37GL 

Assim, obtivemos um identificador de conteúdo com um diretório no qual a página html index.html com o texto "Hello World".


Teste: / ipfs / z6S3Z3W1zuRxio8AJC41jRTdyU9pZWnU6sNbvyGyypEdD8JVNdW42ZmGYWKWGbVDELLvJNWcMspaZMUPZKt7JQmhdyXCqqjj37gL


Além disso, esse hash também pode ser incorporado em outro bloco ou gravado no registro DNS DNS Link. Assim, em um bloco, você pode ajustar um site simples e pequeno.


Buffers de protocolo e bloco DAG


O bloco DAG também pode ser montado manualmente. Um bloco DAG são dados de buffers de protocolo . A camada superior é merkledag.proto, que possui unixfs.proto em Dados.


Buffers de protocolo


Qualquer protobuffer começa com o identificador de campo varint. Geralmente, um identificador ocupa um byte, pois seu valor total é menor que 0x80. No nosso caso, o primeiro byte é 0x12. Os 3 bits inferiores deste campo são do tipo O restante é o ID especificado no arquivo proto.


Delimitado por comprimento

Descriptografamos o identificador:


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

Delimitado por comprimento significa que varint é seguido pelo tamanho do campo em bytes e seu conteúdo diretamente. Esse tipo é usado para várias estruturas aninhadas e dados brutos (sequência, bytes, mensagens incorporadas, campos repetidos compactados). O que o arquivo proto já define nele.


Varint

Decifre o identificador de outro tipo:


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

Varint significa que segue imediatamente o valor em varint. Este contêiner é usado para escrever muitos tipos de valores (int32, int64, uint32, uint64, sint32, sint64, bool, enum). Que também define o arquivo proto.


Vamos analisar o block.dag que traduzimos para o HEX acima


Para analisar um bloco, você pode usar um site que analise automaticamente qualquer Buffer de Protocolo sem usar arquivos proto.


 0x"123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801" 

Desmontamos o bloco e mapeamos os identificadores dos arquivos 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) 

Assim, um bloco com dois arquivos terá a seguinte aparência:


 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) 

Ou seja, o campo PBNode.Links (0x12) é repetido tantas vezes quanto o número de arquivos a serem colocados no bloco.


Para verificar, adicione no início de "F 01 70 00" (HEX CIDv1 DAG Identity) e o tamanho do bloco 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 

Confira: / IPFs / F0170007E123B0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E1206312E68746D6C1800123B0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E1206322E68746D6C18000A020801


Conclusão


Espero ter fornecido informações suficientes para que seja possível implementar a criação de blocos e identificadores.

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


All Articles