IPFS IPLD - merkle-link

merkle-link 는 두 객체를 연결하는 방법입니다. 대상 객체와 원본 객체는 암호화 된 해시의 내용을 사용하여 주소 지정됩니다. 동시에 대상 객체의 해시도 소스 객체에 포함됩니다. merkle-link 를 통한 콘텐츠 주소 지정은 다음을 수행 할 수 있습니다.

  • 암호화 무결성 검사: Resolver 된 링크의 값은 해시로 테스트 할 수 있습니다. 이렇게하면 해시를 통해 링크되지 않은 데이터를 다른 사용자에게 줄 수 없기 때문에 git 또는 bittorrent 와 같이 광범위하고 안전한 신뢰할 수없는 데이터 교환이 가능합니다.
  • 변경 불가능한 데이터 구조: merkle 링크가 있는 데이터 구조는 변경 될 수 없으며 분산 시스템의 중요한 속성입니다. 이는 분산 변수 상태 (예 : CRDT) 및 장기 아카이브를 의미하는 버전 제어에 유용합니다.

merkle-link 는 다음 IPLD 객체 모델로 표현됩니다: “link value” 포함/매핑, 예:

링크는 json 에서 “link object” 로 표현 될 수 있습니다.

{ 
   "/" : "/ipfs/QmUmg7BZC1YP1ca66rRtWKxpXp77WgVHrnv263JtDuvs2k"
}
// "/"는 링크 키입니다.
// "/ipfs/QmUmg7BZC1YP1ca66rRtWKxpXp77WgVHrnv263JtDuvs2k" 링크 값입니다.

foo/baz 에 링크가 있는 객체:

{
  "foo": {
      "bar": "/ipfs/QmUmg7BZC1YP1ca66rRtWKxp77WgVHrnv263JtDuvs2k", // 링크가 아닙니다.
      "baz": {"/": "/ipfs/QmUmg7BZC11ca66rRtWKxpXp77WgVHrnv263JtDuvs2k"} // 링크
    }
}

다음 구조에서는 files/cat.jpg 에 또 다른 가상 “link object” 가 있으며 실제 링크는 files/cat.jpg/link 에 있습니다.

{
  "files": {
    "cat.jpg": { // 링크 된 속성은 다른 객체에 포함됩니다.
      "link": {
      "/": "/ipfs/QmUmg7BZC1YP1ca66rRtWKxpXp77WgVHrnv263JtDuvs2k"}, // 링크
      "mode": 0755,
      "owner": "jbenet"
    }
  }
}

링크가 수정되어 링크 경로가 유효하지 않으면 맵 자체가 오브젝트로 바뀝니다.

이 링크는 멀티 허브 일 수 있습니다. 즉, 링크는 /ipfs 레벨 또는 객체의 절대 경로에 있다고 가정합니다. 그러나 현재 /ipfs 계층 경로만 사용할 수 있습니다.

응용 프로그램이 / 를 사용하여 다른 내용을 나타내야 할 경우 응용 프로그램 자체에서 해상도가 충돌하지 않도록해야 합니다.


IPFS Application 계층 - IPLD

많은 대중적인 시스템 (git, bittorrent, ipfs, tahoe-lafs, sfsro) 이 merkle-tree 와 해시 링크 관련된 데이터 구조를 사용합니다. IPLD (Inter Planetary Linked Data) 는 다음과 같은 개념을 정의합니다:

  • merkle-links: merkle-graph 의 핵심 단위
  • merkle-dag: merkle-links 의 지도
  • merkle-paths: 유닉스 스타일 경로는 merkle-dag 를 쉽게 탐색 할 수 있음
  • IPLD Data Model: merkle-dag 를 표현하기위한 유연한 JSON 기반 데이터 모델
  • IPLD Serialized Formats: JSON, CBOR, CSON, YAML, Protobuf, XML, RDF 등과 같이 IPLD 객체가 사용할 수 있는 형식의 목록
  • IPLD 신뢰형식: 데이터에 대해 동일한 해석 논리를 보장하는 시퀀스 형식에 대한 명확한 설명으로 merkle-link 및 기타 암호화 응용 프로그램에 중요

요약하면: IPLD 는 merkle-link 가 통과 할 수있는 JSON 파일 객체입니다.

IPLD 의 구성 요소는 다음 그림과 같이 구성됩니다. CID, IPLD 트리, IPLD Resolver.


IPFS Multiformats - multistream

multistream 은 multicodec 을 사용하여 자가 기술 함수를 구현합니다. 다음은 자바 스크립트를 기반으로 한 예제입니다. 첫째, 내부에 json 객체인 새로운 버퍼 객체를 작성한 다음 protobuf 접두어를 지정하여 multistream 을 구성하고 네트워크를 통해 전송할 수 있도록 합니다. 구문 분석에서 먼저 코덱 접두어를 취한 다음 접두사를 제거하여 특정 데이터 컨텐츠를 가져올 수 있습니다.

// encode some json
const buf = new Buffer(JSON.stringify({ hello: 'world' }))

const prefixedBuf = multistream.addPrefix('json', str) // prepends multicodec ('json')
console.log(prefixedBuf)
// <Buffer 06 2f 6a 73 6f 6e 2f 7b 22 68 65 6c 6c 6f 22 3a 22 77 6f 72 6c 64 22 7d>

const.log(prefixedBuf.toString('hex'))
// 062f6a736f6e2f7b2268656c6c6f223a22776f726c64227d

// let's get the Codec and then get the data back

const codec = multicodec.getCodec(prefixedBuf)
console.log(codec)
// json

console.log(multistream.rmPrefix(prefixedBuf).toString())
// "{ \"hello\": \"world\" }

결과 출력:

hex:   062f6a736f6e2f7b2268656c6c6f223a22776f726c64227d
ascii: /json\n"{\"hello\":\"world\"}"

1. 멀티 스트림 소스 코드 분석

소스 경로: src\github.com\multiformats\go-multistream\multistream.go

go-multistream 설치

get github.com/multiformats/go-multistream

멀티플렉서를 사용하여 사용자가 다른 “프로토콜”을 처리 할 수 있는 핸들러를 추가 할 수 있습니다:

package main

import (
    "fmt"
    "io"
    "io/ioutil"
    "net"
    ms "github.com/multiformats/go-multistream"
)

// 사용되지 않는 프로토콜에 대한 다른 핸들러를 작성하기 위해 멀티플렉서를 작성
// "/cats" 및 "/docs" 두 가지 프로토콜을 만듭니다.
func main() {
    mux := ms.NewMultistreamMuxer()
    mux.AddHandler("/cats", func(proto string, rwc io.ReadWriteCloser) error {
        fmt.Fprintln(rwc, proto, ": HELLO I LIKE CATS")
        return rwc.Close()
    })
    mux.AddHandler("/dogs", func(proto string, rwc io.ReadWriteCloser) error {
        fmt.Fprintln(rwc, proto, ": HELLO I LIKE DOGS")
        return rwc.Close()
    })

    list, err := net.Listen("tcp", ":8765")
    if err != nil {
        panic(err)
    }

    go func() {
        for {
            con, err := list.Accept()
            if err != nil {
                panic(err)
            }

            go mux.Handle(con)
        }
    }()

    // 테스트 시작
    conn, err := net.Dial("tcp", ":8765")
    if err != nil {
        panic(err)
    }

    // /cats 프로토콜
    mstream := ms.NewMSSelect(conn, "/cats")
    cats, err := ioutil.ReadAll(mstream)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s", cats)
    mstream.Close()

    conn, err = net.Dial("tcp", ":8765")
    if err != nil {
        panic(err)
    }
    defer conn.Close()
    // /dogs 프로토콜
    err = ms.SelectProtoOrFail("/dogs", conn)
    if err != nil {
        panic(err)
    }
    dogs, err := ioutil.ReadAll(conn)
    if err != nil {
        panic(err)
    }
    fmt.Printf("%s", dogs)
    conn.Close()
}

확인 테스트는 아래와 같이 수행합니다.

$ go run multistream.go
/cats :HELLO I LIKE CATS
/dogs :HELLO I LIKE DOGS

IPFS Multiformats - multicodec

multicodec 은 자가 기술 형식을 포함하는 자가 기술 코덱입니다. multicodec 식별자는 varint 입니다. 실제로 base58 btc 인코딩의 경우 z, protobuf 의 경우 0x50 등과 같이 데이터 내용의 형식을 결정하기 위한 1-2 바이트가 있는 테이블입니다.

이는 https://github.com/multiformats/multicodec/blob/master/table.csv 에서 볼 수 있습니다.

multicodec 으로 식별되는 많은 양의 데이터는 다음과 같습니다.

<multicodec><encoded-data> 

# 생략할 수 있음:
<mc><data>

또 다른 유용한 시나리오는 multicodec 을 키 액세스의 일부로 사용하는 것입니다. 예를 들면 다음과 같습니다.

# suppose we have a value and a key to retrieve it
"<key>" -> <value>

# we can use multicodec with the key to know what codec the value is in
"<mc><key>" -> <value>

multicodec 은 multihash 및 multiaddr 과 잘 작동하며 여러 코드를 사용하여 이 값 앞에 접두어를 붙이면 자신이 무엇인지 알 수 있습니다.


IPFS Multiformats - multibase

multibase 는 데이터를 다른 형식으로 인코딩하는 데 편리한 인코딩 형식을 나타냅니다. 예를 들어 2 진수, 8 진수, 10 진수, 16 진수 및 base58btc, base64 인코딩으로 생각할 수 있습니다.

지원되는 인코딩 형식은 다음과 같습니다.

Multibase Table v1.0.0-RC (semver)

encoding      codes   name
identity      0x00    8-bit binary (encoder and decoder keeps data unmodified)
base1         1       unary tends to be 11111
base2         0       binary has 1 and 0
base8         7       highest char in octal
base10        9       highest char in decimal
base16        F, f    highest char in hex
base32        B, b    rfc4648 - no padding - highest letter
base32pad     C, c    rfc4648 - with padding
base32hex     V, v    rfc4648 - no padding - highest char
base32hexpad  T, t    rfc4648 - with padding
base32z       h       z-base-32 - used by Tahoe-LAFS - highest letter
base58flickr  Z       highest char
base58btc     z       highest char
base64        m       rfc4648 - no padding
base64pad     M       rfc4648 - with padding - MIME encoding
base64url     u       rfc4648 - no padding
base64urlpad  U       rfc4648 - with padding

1. multibase 형식

<varint-base-encoding-code><base-encoded-data>

  • varint-base-encoding-code: 인코딩 형식 (위의 내용 참조)
  • base-encoded-data: 데이터

예:

4D756C74696261736520697320617765736F6D6521205C6F2F  # base16 (hex)
JV2WY5DJMJQXGZJANFZSAYLXMVZW63LFEEQFY3ZP            # base32
YAjKoNbau5KiqmHPmSxYCvn66dA1vLmwbt                  # base58
TXVsdGliYXNlIGlzIGF3ZXNvbWUhIFxvLw==                # base64
F4D756C74696261736520697320617765736F6D6521205C6F2F # base16 F
BJV2WY5DJMJQXGZJANFZSAYLXMVZW63LFEEQFY3ZP           # base32 B
zYAjKoNbau5KiqmHPmSxYCvn66dA1vLmwbt                 # base58 z
MTXVsdGliYXNlIGlzIGF3ZXNvbWUhIFxvLw==               # base64 M

시작되는 알파벳은 다음과 같습니다: F, B, z, M

2. multibase 설치

Golang 을 사용하여 multibase 를 사용합니다.

multibase 설치는 다음을 사용합니다.

go get github.com/multiformats/go-multibase

multiaddr 패키지는 패키지 gx 에 의존하기 때문에 multiaddr 을 사용하려면 다음이 필요합니다.

go get -u github.com/whyrusleeping/gx
go get -u github.com/whyrusleeping/gx-go
cd <your-project-repository>
gx init
gx import github.com/multiformats/go-multibase
gx install --global
gx-go --rewrite

3. multibase 설치 및 사용

원본 경로: src\github.com\multiformats\go-multibase\multibase.go

기본 인코딩 테이블:

// specified in standard are left out
var Encodings = map[string]Encoding{
    "identity":          0x00,
    "base16":            'f',
    "base16upper":       'F',
    "base32":            'b',
    "base32upper":       'B',
    "base32pad":         'c',
    "base32padupper":    'C',
    "base32hex":         'v',
    "base32hexupper":    'V',
    "base32hexpad":      't',
    "base32hexpadupper": 'T',
    "base58flickr":      'Z',
    "base58btc":         'z',
    "base64":            'm',
    "base64url":         'u',
    "base64pad":         'M',
    "base64urlpad":      'U',
}

코드:

// Encode encodes a given byte slice with the selected encoding and returns a
// multibase string (<encoding><base-encoded-string>). It will return
// an error if the selected base is not known.
func Encode(base Encoding, data []byte) (string, error) 

설치 확인 테스트는 아래와 같이 수행합니다.

// Decode takes a multibase string and decodes into a bytes buffer.
// It will return an error if the selected base is not known.
func Decode(data string) (Encoding, []byte, error)