Interplanetares Dateisystem - trivialer Hash (Identität), DAG-Block und Protokollpuffer

Kürzlich hat IPFS die Unterstützung für einen trivialen (Identitäts-) Hash hinzugefügt. In meinem Artikel werde ich darüber sprechen und zeigen, wie es verwendet werden kann.


Ich möchte Sie daran erinnern: InterPlanetary File System ist ein neues dezentrales Filesharing-Netzwerk (HTTP-Server, Content Delivery Network ). Ich habe die Geschichte darüber im Artikel "Interplanetary File System IPFS" begonnen .

Wenn Hashing eine Hash-Funktion durchläuft , werden die Daten normalerweise irreversibel "komprimiert", und als Ergebnis wird eine kurze Kennung erhalten. Mit dieser Kennung können Sie Daten im Netzwerk finden und deren Integrität überprüfen.


Ein trivialer Hash sind die Daten selbst. Die Daten ändern sich in keiner Weise und dementsprechend entspricht die Größe des "Hash" der Größe der Daten.


Ein trivialer Hash hat dieselbe Funktion wie Data: URL . Die Inhaltskennung enthält in diesem Fall die Daten selbst anstelle eines Hashs. Auf diese Weise können Sie untergeordnete Blöcke im übergeordneten Element verschachteln und diese sofort nach Erhalt des übergeordneten Elements verfügbar machen. Sie können Standortdaten auch direkt in den DNS-Eintrag aufnehmen.


Codieren Sie beispielsweise die Textzeichenfolge "Hello World" in der Kennung des Inhalts (CID) mit einem trivialen Hash.
Bild


ID-Struktur:


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

Beginnen wir am Ende.


[Hash]


Der triviale Hash in unserem Fall ist der String selbst. Lassen Sie es uns in HEX übersetzen .


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

Dies ist der HEX dieser utf-8- codierten Zeichenfolge. Damit der Browser jedoch sicher weiß, dass es sich um eine utf-8-Zeile handelt, fügen Sie sie am Anfang hinzu: 0xEFBBBF . Dies ist ein Byte Sequence Marker (BOM).


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

[Varint Hash Länge]


Jetzt können wir die Länge des "Hash" berechnen. Alle zwei HEX-Zeichen sind ein Byte. Dementsprechend ist die resultierende Zeichenfolge 22 Byte lang. In HEX ist es 0x16 .


Fügen Sie 0x16 am Zeilenanfang hinzu.


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

[varint hash id]


Jetzt brauchen wir die Hash-ID. Der triviale Hash oder die Identität in der Hash-Tabelle hat den Bezeichner 0x00 .


Fügen Sie 0x00 am Zeilenanfang hinzu.


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

Dies ist bereits ein Multi-Hash- Teil der Kennung. Sie können HEX in Base58 umcodieren und der Multi-Hash ist bereit. Ipfs erkennt es jedoch nicht außerhalb der Inhaltskennung (CID).


Lass uns weitermachen.


[varint Inhaltstyp]


Schauen Sie sich nun die Multicodec- Tabelle an, um den Inhaltstyp zu erhalten. In unserem Fall handelt es sich um Rohdaten, und der Bezeichner ist 0x55 .


Fügen Sie 0x55 am Zeilenanfang hinzu.


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

[Varint-Version von CID]


Wir codieren das Format der ersten Version der Inhaltskennung . Fügen Sie daher 0x01 hinzu.


Fügen Sie am 0x01 hinzu.


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

Und so sind wir schon am Ziel.


[Basispräfix]


Es gibt an, welche Option zum Codieren von Binärdaten in Text verwendet wird.


HEX (F)


Wir können den HEX-Begriff direkt verwenden, indem wir das "F" -Symbol am Anfang des HEX-Basispräfixes hinzufügen


 F01550016EFBBBFD09FD180D0B8D0B2D0B5D18220D0BCD0B8D180 

Wir haben eine HEX-Kennung für den Inhalt, der die Zeile utf-8 enthält: "Hallo Welt"


Testen: / ipfs / F01550016EFBBBFD09FD180D0B8D0B2D0B5D18220D0BCD0B8D180


Base58btc (z)


Base58btc wird daher kürzer sein


Wir übersetzen unseren HEX-String in base58btc. Sie können den Online-Konverter verwenden .


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

Fügen Sie das Basispräfixzeichen base58btc "z" am Zeilenanfang hinzu


 z3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P 

Wir haben base58btc eine Inhaltskennung, die eine utf-8-Zeile enthält: "Hallo Welt"


Testen: / ipfs / z3NDGAEgXCxbPucFFCQc9s5ScqZjqVFNr56P


DAG-Block


Der Text ist gut, aber um eine HTML-Seite zu codieren, müssen wir ihre Daten in den DAG-Verzeichnisblock einbetten.


Hier ist unser HTML:


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

In ähnlicher Weise erhalten wir gemäß den obigen Anweisungen die Inhaltskennung in base58btc für diesen Text:


 zeExnPvBXdTRwCBhfkJ1fHFDaXpdW4ghvQjfaCRHYxtQnd3H4w1MPbLczSqyCqVo 

Schreiben Sie nun die JSON-Datei:


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

  1. Die "Daten" geben den Typ des DAG-Blocks an - das Verzeichnis.
  2. "links" ist ein Array von Dateilinks.
  3. "Name" ist der Name der Datei.
  4. "Cid" enthält die Inhaltskennung

Konvertieren Sie JSON mit dem ipfs dag put -f"protobuf" über IPFS in einen DAG-Block.


Ich habe einen Multihash: QmXXixn4rCzGguhxQPjXQ8Mr5rdqwZfJTKkeB6DfZLt8EZ


Zu diesem Zeitpunkt haben wir einen Block erhalten, in dem ein Verzeichnis mit einer Datei in den Block eingeschrieben ist.


Entladen Sie anschließend mit diesem Multicash den fertigen Block


 ipfs block get QmXXixn4rCzGguhxQPjXQ8Mr5rdqwZfJTKkeB6DfZLt8EZ > block.dag 

Wir übersetzen den Inhalt von block.dag in HEX:


 0x"123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801" 

Hinzufügen:


  1. CID-Version (0x01)
  2. DAG-Inhaltstyp (0x70)
  3. trivialer Hash (0x00)
  4. Datengröße 69 Bytes (0x45)

 0x"01 70 00 45 123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801" 

In Base58btc konvertieren und das Präfix "z" hinzufügen


 z6S3Z3W1zuRxio8AJC41jRTdyU9pZWnU6sNbvyGyypEdD8JVNdW42ZmGYWKWGbVDELLvJNWcMspaZMUPZKt7JQmhdyXCqq7j37GL 

So haben wir eine Inhaltskennung mit einem Verzeichnis erhalten, in dem sich die HTML-Seite index.html mit dem Text "Hello World" befindet.


Testen: / ipfs / z6S3Z3W1zuRxio8AJC41jRTdyU9pZWnU6sNbvyGyypEdD8JVNdW42ZmGYWKWGbVDELLvJNWcMspaZMUPZKt7JQmhdyXCqqjj37gL


Ferner kann dieser Hash auch in einen anderen Block eingebettet oder im DNS-DNS-Link-Eintrag aufgezeichnet werden. So können Sie in einem Block eine kleine einfache Site einfügen.


DAG-Block- und Protokollpuffer


Der DAG-Block kann auch manuell zusammengebaut werden. Ein DAG-Block besteht aus Protokollpufferdaten . Die oberste Ebene ist merkledag.proto mit unixfs.proto in Data.


Protokollpuffer


Jeder Protobuffer beginnt mit der varint-Feldkennung. Oft nimmt ein Bezeichner ein Byte ein, da sein Gesamtwert kleiner als 0x80 ist. In unserem Fall ist das erste Byte 0x12. Die unteren 3 Bits dieses Feldes sind vom Typ. Der Rest ist die in der Protodatei angegebene ID.


Längenbegrenzt

Wir entschlüsseln die Kennung:


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

Längenbegrenzt bedeutet, dass auf varint die Größe des Feldes in Bytes und dessen Inhalt direkt folgt. Dieser Typ wird sowohl für verschiedene verschachtelte Strukturen als auch für Rohdaten (Zeichenfolge, Bytes, eingebettete Nachrichten, gepackte wiederholte Felder) verwendet. Was die Proto-Datei bereits darin definiert.


Varint

Entschlüsseln Sie die Kennung eines anderen Typs:


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

Varint bedeutet, dass unmittelbar auf den Wert in varint folgt. Dieser Container wird zum Schreiben vieler Arten von Werten verwendet (int32, int64, uint32, uint64, sint32, sint64, bool, enum). Was darin auch die Protodatei definiert.


Wir werden block.dag analysieren, das wir oben in HEX übersetzt haben


Um einen Block zu analysieren, können Sie eine Site verwenden, die automatisch jeden Protokollpuffer analysiert, ohne Protodateien zu verwenden.


 0x"123F0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E120A696E6465782E68746D6C18000A020801" 

Wir zerlegen den Block und ordnen die Bezeichner den Protodateien zu.


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) 

Dementsprechend sieht ein Block mit zwei Dateien folgendermaßen aus:


 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) 

Das heißt, das Feld PBNode.Links (0x12) wird so oft wiederholt wie die Anzahl der Dateien, die in den Block eingefügt werden sollen.


Fügen Sie zur Überprüfung am Anfang von "F 01 70 00" (HEX CIDv1-DAG-Identität) und der Größe des DAG-Blocks "7E" (126 Byte) hinzu.


 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 

Check: / ipfs / F0170007E123B0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E1206312E68746D6C1800123B0A2F0155002BEFBBBF3C623E3C693E3C753ED09FD180D0B8D0B2D0B5D18220D0BCD0B8D1803C2F753E3C2F693E3C2F623E1206322E68746D6C18000A020801


Fazit


Ich hoffe, ich habe genügend Informationen gegeben, damit die Erstellung von Blöcken und Bezeichnern implementiert werden kann.

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


All Articles