Commit d66d955d authored by tavit ohanian's avatar tavit ohanian

reference basis

parents 39c18c36 13057320
Pipeline #863 failed with stages
in 0 seconds
# File managed by web3-bot. DO NOT EDIT.
# See https://github.com/protocol/.github/ for details.
# Automatically merge pull requests opened by web3-bot, as soon as (and only if) all tests pass.
# This reduces the friction associated with updating with our workflows.
on: [ pull_request ]
name: Automerge
jobs:
automerge-check:
if: github.event.pull_request.user.login == 'web3-bot'
runs-on: ubuntu-latest
outputs:
status: ${{ steps.should-automerge.outputs.status }}
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Check if we should automerge
id: should-automerge
run: |
for commit in $(git rev-list --first-parent origin/${{ github.event.pull_request.base.ref }}..${{ github.event.pull_request.head.sha }}); do
committer=$(git show --format=$'%ce' -s $commit)
echo "Committer: $committer"
if [[ "$committer" != "web3-bot@users.noreply.github.com" ]]; then
echo "Commit $commit wasn't committed by web3-bot, but by $committer."
echo "::set-output name=status::false"
exit
fi
done
echo "::set-output name=status::true"
automerge:
needs: automerge-check
runs-on: ubuntu-latest
if: ${{ needs.automerge-check.outputs.status == 'true' }}
steps:
- name: Wait on tests
uses: lewagon/wait-on-check-action@bafe56a6863672c681c3cf671f5e10b20abf2eaa # v0.2
with:
ref: ${{ github.event.pull_request.head.sha }}
repo-token: ${{ secrets.GITHUB_TOKEN }}
wait-interval: 10
running-workflow-name: 'automerge' # the name of this job
- name: Merge PR
uses: pascalgn/automerge-action@741c311a47881be9625932b0a0de1b0937aab1ae # v0.13.1
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
MERGE_LABELS: ""
MERGE_METHOD: "squash"
MERGE_DELETE_BRANCH: true
# File managed by web3-bot. DO NOT EDIT.
# See https://github.com/protocol/.github/ for details.
on: [push, pull_request]
name: Go Checks
jobs:
unit:
runs-on: ubuntu-latest
name: All
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: actions/setup-go@v2
with:
go-version: "1.16.x"
- name: Install staticcheck
run: go install honnef.co/go/tools/cmd/staticcheck@434f5f3816b358fe468fa83dcba62d794e7fe04b # 2021.1 (v0.2.0)
- name: Check that go.mod is tidy
uses: protocol/multiple-go-modules@v1.0
with:
run: |
go mod tidy
if [[ -n $(git ls-files --other --exclude-standard --directory -- go.sum) ]]; then
echo "go.sum was added by go mod tidy"
exit 1
fi
git diff --exit-code -- go.sum go.mod
- name: gofmt
if: ${{ success() || failure() }} # run this step even if the previous one failed
run: |
out=$(gofmt -s -l .)
if [[ -n "$out" ]]; then
echo $out | awk '{print "::error file=" $0 ",line=0,col=0::File is not gofmt-ed."}'
exit 1
fi
- name: go vet
if: ${{ success() || failure() }} # run this step even if the previous one failed
uses: protocol/multiple-go-modules@v1.0
with:
run: go vet ./...
- name: staticcheck
if: ${{ success() || failure() }} # run this step even if the previous one failed
uses: protocol/multiple-go-modules@v1.0
with:
run: |
set -o pipefail
staticcheck ./... | sed -e 's@\(.*\)\.go@./\1.go@g'
# File managed by web3-bot. DO NOT EDIT.
# See https://github.com/protocol/.github/ for details.
on: [push, pull_request]
name: Go Test
jobs:
unit:
strategy:
fail-fast: false
matrix:
os: [ "ubuntu", "windows", "macos" ]
go: [ "1.15.x", "1.16.x" ]
runs-on: ${{ matrix.os }}-latest
name: ${{ matrix.os}} (go ${{ matrix.go }})
steps:
- uses: actions/checkout@v2
with:
submodules: recursive
- uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
- name: Go information
run: |
go version
go env
- name: Run tests
uses: protocol/multiple-go-modules@v1.0
with:
run: go test -v -coverprofile coverage.txt ./...
- name: Run tests (32 bit)
if: ${{ matrix.os != 'macos' }} # can't run 32 bit tests on OSX.
uses: protocol/multiple-go-modules@v1.0
env:
GOARCH: 386
with:
run: go test -v ./...
- name: Run tests with race detector
if: ${{ matrix.os == 'ubuntu' }} # speed things up. Windows and OSX VMs are slow
uses: protocol/multiple-go-modules@v1.0
with:
run: go test -v -race ./...
- name: Upload coverage to Codecov
uses: codecov/codecov-action@a1ed4b322b4b38cb846afb5a0ebfa17086917d27 # v1.5.0
with:
file: coverage.txt
env_vars: OS=${{ matrix.os }}, GO=${{ matrix.go }}
coverage.out
Copyright 2020 Protocol Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright 2020 Protocol Labs
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# go-codec-dagpb
# go-dagpb
dms3 go-codec-dagpb
\ No newline at end of file
**An implementation of the IPLD [DAG-PB](https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-pb.md) spec for [go-ipld-prime](https://github.com/ipld/go-ipld-prime/)**
Use `Decode(ipld.NodeAssembler, io.Reader)` and `Encode(ipld.Node, io.Writer)` directly, or import this package to have this codec registered into the go-ipld-prime CID link loader.
Nodes encoded with this codec _must_ conform to the DAG-PB spec. Specifically, they should have the non-optional fields shown in the DAG-PB schema:
```ipldsch
type PBNode struct {
Links [PBLink]
Data optional Bytes
}
type PBLink struct {
Hash Link
Name optional String
Tsize optional Int
}
```
Use `dagpb.Type.PBNode` and friends directly for strictness guarantees. Basic `ipld.Node`s will need to have the appropraite fields (and no others) to successfully encode using this codec.
## License & Copyright
Copyright © 2020 Protocol Labs
Licensed under either of
* Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / http://www.apache.org/licenses/LICENSE-2.0)
* MIT ([LICENSE-MIT](LICENSE-MIT) / http://opensource.org/licenses/MIT)
### Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
package dagpb
import (
"bytes"
"encoding/hex"
"testing"
"github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/fluent"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
)
type pbNode struct {
links []pbLink
data []byte
}
func mkcid(t *testing.T, cidStr string) cid.Cid {
c, err := cid.Decode(cidStr)
if err != nil {
t.Fatal(err)
}
return c
}
func validate(t *testing.T, actual ipld.Node, expected pbNode) {
mi := actual.MapIterator()
_, isTyped := actual.(*_PBNode)
hasLinks := false
hasData := false
for !mi.Done() {
key, val, err := mi.Next()
if err != nil {
t.Fatal(err)
}
keyStr, err := key.AsString()
if err != nil {
t.Fatal(err)
}
if keyStr == "Links" {
if val.Kind() != ipld.Kind_List {
t.Fatal("Links is not a list")
}
if val.IsAbsent() {
t.Fatal("Links is absent")
}
if val.IsNull() {
t.Fatal("Links is null")
}
if val.Length() != int64(len(expected.links)) {
t.Fatal("non-empty Links list")
}
hasLinks = true
} else if keyStr == "Data" {
if isTyped && expected.data == nil {
if !val.IsAbsent() {
t.Fatalf("Empty Data is not marked as absent")
}
if val.Kind() != ipld.Kind_Null {
t.Fatal("Empty Data is not null")
}
if val.IsNull() {
t.Fatal("Empty Data is null")
}
}
hasData = !isTyped || !val.IsAbsent()
if hasData {
if expected.data == nil {
t.Fatal("Got unexpected Data")
} else {
byts, err := val.AsBytes()
if err != nil {
t.Fatal(err)
} else if !bytes.Equal(expected.data, byts) {
t.Fatal("Got unexpected Data contents")
}
}
}
} else {
t.Fatalf("Unexpected map key: %v", keyStr)
}
}
if !hasLinks {
t.Fatal("Did not find Links")
}
if expected.data != nil && !hasData {
t.Fatal("Did not find Data")
}
}
func runTest(t *testing.T, bytsHex string, expected pbNode) {
byts, _ := hex.DecodeString(bytsHex)
roundTrip := func(t *testing.T, node ipld.Node) {
var buf bytes.Buffer
if err := Encode(node, &buf); err != nil {
t.Fatal(err)
}
// fmt.Printf("CMP\n\tFrom: %v\n\tTo: %v\n", hex.EncodeToString(byts), hex.EncodeToString(buf.Bytes()))
if !bytes.Equal(buf.Bytes(), byts) {
t.Fatal("Round-trip resulted in different bytes")
}
}
t.Run("basicnode", func(t *testing.T) {
nb := basicnode.Prototype__Map{}.NewBuilder()
err := Decode(nb, bytes.NewReader(byts))
if err != nil {
t.Fatal(err)
}
node := nb.Build()
validate(t, node, expected)
roundTrip(t, node)
})
t.Run("typed", func(t *testing.T) {
nb := Type.PBNode.NewBuilder()
err := Decode(nb, bytes.NewReader(byts))
if err != nil {
t.Fatal(err)
}
node := nb.Build()
validate(t, node, expected)
roundTrip(t, node)
})
}
func TestEmptyNode(t *testing.T) {
runTest(t, "", pbNode{})
}
func TestNodeWithData(t *testing.T) {
runTest(t, "0a050001020304", pbNode{data: []byte{00, 01, 02, 03, 04}})
}
func TestNodeWithDataZero(t *testing.T) {
runTest(t, "0a00", pbNode{data: []byte{}})
}
func TestNodeWithLink(t *testing.T) {
expected := pbNode{}
expected.links = append(expected.links, pbLink{hash: mkcid(t, "QmWDtUQj38YLW8v3q4A6LwPn4vYKEbuKWpgSm6bjKW6Xfe")})
runTest(t, "12240a2212207521fe19c374a97759226dc5c0c8e674e73950e81b211f7dd3b6b30883a08a51", expected)
}
func TestNodeWithLinkAndData(t *testing.T) {
expected := pbNode{data: []byte("some data")}
expected.links = append(expected.links, pbLink{hash: mkcid(t, "QmWDtUQj38YLW8v3q4A6LwPn4vYKEbuKWpgSm6bjKW6Xfe")})
runTest(t, "12240a2212207521fe19c374a97759226dc5c0c8e674e73950e81b211f7dd3b6b30883a08a510a09736f6d652064617461", expected)
}
func TestNodeWithTwoUnsortedLinks(t *testing.T) {
encoded := "12340a2212208ab7a6c5e74737878ac73863cb76739d15d4666de44e5756bf55a2f9e9ab5f431209736f6d65206c696e6b1880c2d72f12370a2212208ab7a6c5e74737878ac73863cb76739d15d4666de44e5756bf55a2f9e9ab5f44120f736f6d65206f74686572206c696e6b18080a09736f6d652064617461"
expected := pbNode{data: []byte("some data")}
expected.links = append(expected.links, pbLink{name: "some link", hasName: true, hash: mkcid(t, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39U"), tsize: 100000000, hasTsize: true})
expected.links = append(expected.links, pbLink{name: "some other link", hasName: true, hash: mkcid(t, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V"), tsize: 8, hasTsize: true})
runTest(t, encoded, expected)
// assembled in a rough order, Data coming first, links badly sorted
node := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(fma fluent.MapAssembler) {
fma.AssembleEntry("Data").AssignBytes([]byte("some data"))
fma.AssembleEntry("Links").CreateList(2, func(fla fluent.ListAssembler) {
fla.AssembleValue().CreateMap(3, func(fma fluent.MapAssembler) {
fma.AssembleEntry("Name").AssignString("some other link")
fma.AssembleEntry("Tsize").AssignInt(8)
fma.AssembleEntry("Hash").AssignLink(cidlink.Link{Cid: mkcid(t, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39V")})
})
fla.AssembleValue().CreateMap(3, func(fma fluent.MapAssembler) {
fma.AssembleEntry("Name").AssignString("some link")
fma.AssembleEntry("Tsize").AssignInt(100000000)
fma.AssembleEntry("Hash").AssignLink(cidlink.Link{Cid: mkcid(t, "QmXg9Pp2ytZ14xgmQjYEiHjVjMFXzCVVEcRTWJBmLgR39U")})
})
})
})
var buf bytes.Buffer
if err := Encode(node, &buf); err != nil {
t.Fatal(err)
}
if hex.EncodeToString(buf.Bytes()) != encoded {
t.Fatal("did not encode to expected bytes")
}
}
func TestNodeWithStableSortedLinks(t *testing.T) {
cids := []string{
"QmUGhP2X8xo9dsj45vqx1H6i5WqPqLqmLQsHTTxd3ke8mp",
"QmP7SrR76KHK9A916RbHG1ufy2TzNABZgiE23PjZDMzZXy",
"QmQg1v4o9xdT3Q14wh4S7dxZkDjyZ9ssFzFzyep1YrVJBY",
"QmdP6fartWRrydZCUjHgrJ4XpxSE4SAoRsWJZ1zJ4MWiuf",
"QmNNjUStxtMC1WaSZYiDW6CmAUrvd5Q2e17qnxPgVdwrwW",
"QmWJwqZBJWerHsN1b7g4pRDYmzGNnaMYuD3KSbnpaxsB2h",
"QmRXPSdysBS3dbUXe6w8oXevZWHdPQWaR2d3fggNsjvieL",
"QmTUZAXfws6zrhEksnMqLxsbhXZBQs4FNiarjXSYQqVrjC",
"QmNNk7dTdh8UofwgqLNauq6N78DPc6LKK2yBs1MFdx7Mbg",
"QmW5mrJfyqh7B4ywSvraZgnWjS3q9CLiYURiJpCX3aro5i",
"QmTFHZL5CkgNz19MdPnSuyLAi6AVq9fFp81zmPpaL2amED",
}
node := fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(fma fluent.MapAssembler) {
fma.AssembleEntry("Data").AssignBytes([]byte("some data"))
fma.AssembleEntry("Links").CreateList(int64(len(cids)), func(fla fluent.ListAssembler) {
for _, cid := range cids {
fla.AssembleValue().CreateMap(3, func(fma fluent.MapAssembler) {
fma.AssembleEntry("Name").AssignString("")
fma.AssembleEntry("Tsize").AssignInt(262158)
fma.AssembleEntry("Hash").AssignLink(cidlink.Link{Cid: mkcid(t, cid)})
})
}
})
})
var buf bytes.Buffer
if err := Encode(node, &buf); err != nil {
t.Fatal(err)
}
nb := basicnode.Prototype__Map{}.NewBuilder()
err := Decode(nb, bytes.NewReader(buf.Bytes()))
if err != nil {
t.Fatal(err)
}
reencNode := nb.Build()
links, _ := reencNode.LookupByString("Links")
if links.Length() != int64(len(cids)) {
t.Fatal("Incorrect number of links after round-trip")
}
iter := links.ListIterator()
for !iter.Done() {
ii, n, _ := iter.Next()
h, _ := n.LookupByString("Hash")
l, _ := h.AsLink()
cl, _ := l.(cidlink.Link)
if cids[ii] != cl.String() {
t.Fatal("CIDs did not retain position after round-trip")
}
}
if hex.EncodeToString(buf.Bytes()) != "122a0a2212205822d187bd40b04cc8ae7437888ebf844efac1729e098c8816d585d0fcc42b5b1200188e8010122a0a2212200b79badee10dc3f7781a7a9d0f020cc0f710b328c4975c2dbc30a170cd188e2c1200188e8010122a0a22122022ad631c69ee983095b5b8acd029ff94aff1dc6c48837878589a92b90dfea3171200188e8010122a0a221220df7fd08c4784fe6938c640df473646e4f16c7d0c6567ab79ec6981767fc3f01a1200188e8010122a0a22122000888c815ad7d055377bdb7b7779fc9740e548cb5dac90c71b9af9f51a879c2d1200188e8010122a0a221220766db372d015c5c700f538336556370165c889334791487a5e48d6080f1c99ea1200188e8010122a0a2212202f533004ceed74279b32c58eb0e3d2a23bc27ba14ab07298406c42bab8d543211200188e8010122a0a2212204c50cfdefa0209766f885919ac8ffc258e9253c3001ac23814f875d414d394731200188e8010122a0a22122000894611dfa192853020cbbade1a9a0a3f359d26e0d38caf4d72b9b306ff5a0b1200188e8010122a0a221220730ddba83e3147bbe10780b97ff0718c74c36037b97b3b79b45c4511806545811200188e8010122a0a22122048ea9d5d423f678d83d559d2349be8325527290b070c90fc1acd968f0bf70a061200188e80100a09736f6d652064617461" {
t.Fatal("Encoded form did not match expected")
}
}
func TestNodeWithUnnamedLinks(t *testing.T) {
dataByts, _ := hex.DecodeString("080218cbc1819201208080e015208080e015208080e015208080e015208080e015208080e01520cbc1c10f")
expected := pbNode{data: dataByts}
expected.links = []pbLink{
{name: "", hasName: true, hash: mkcid(t, "QmSbCgdsX12C4KDw3PDmpBN9iCzS87a5DjgSCoW9esqzXk"), tsize: 45623854, hasTsize: true},
{name: "", hasName: true, hash: mkcid(t, "Qma4GxWNhywSvWFzPKtEswPGqeZ9mLs2Kt76JuBq9g3fi2"), tsize: 45623854, hasTsize: true},
{name: "", hasName: true, hash: mkcid(t, "QmQfyxyys7a1e3mpz9XsntSsTGc8VgpjPj5BF1a1CGdGNc"), tsize: 45623854, hasTsize: true},
{name: "", hasName: true, hash: mkcid(t, "QmSh2wTTZT4N8fuSeCFw7wterzdqbE93j1XDhfN3vQHzDV"), tsize: 45623854, hasTsize: true},
{name: "", hasName: true, hash: mkcid(t, "QmVXsSVjwxMsCwKRCUxEkGb4f4B98gXVy3ih3v4otvcURK"), tsize: 45623854, hasTsize: true},
{name: "", hasName: true, hash: mkcid(t, "QmZjhH97MEYwQXzCqSQbdjGDhXWuwW4RyikR24pNqytWLj"), tsize: 45623854, hasTsize: true},
{name: "", hasName: true, hash: mkcid(t, "QmRs6U5YirCqC7taTynz3x2GNaHJZ3jDvMVAzaiXppwmNJ"), tsize: 32538395, hasTsize: true},
}
runTest(
t,
"122b0a2212203f29086b59b9e046b362b4b19c9371e834a9f5a80597af83be6d8b7d1a5ad33b120018aed4e015122b0a221220ae1a5afd7c770507dddf17f92bba7a326974af8ae5277c198cf13206373f7263120018aed4e015122b0a22122022ab2ebf9c3523077bd6a171d516ea0e1be1beb132d853778bcc62cd208e77f1120018aed4e015122b0a22122040a77fe7bc69bbef2491f7633b7c462d0bce968868f88e2cbcaae9d0996997e8120018aed4e015122b0a2212206ae1979b14dd43966b0241ebe80ac2a04ad48959078dc5affa12860648356ef6120018aed4e015122b0a221220a957d1f89eb9a861593bfcd19e0637b5c957699417e2b7f23c88653a240836c4120018aed4e015122b0a221220345f9c2137a2cd76d7b876af4bfecd01f80b7dd125f375cb0d56f8a2f96de2c31200189bfec10f0a2b080218cbc1819201208080e015208080e015208080e015208080e015208080e015208080e01520cbc1c10f",
expected)
}
func TestNodeWithNamedLinks(t *testing.T) {
dataByts, _ := hex.DecodeString("0801")
expected := pbNode{data: dataByts}
expected.links = []pbLink{
{name: "audio_only.m4a", hasName: true, hash: mkcid(t, "QmaUAwAQJNtvUdJB42qNbTTgDpzPYD1qdsKNtctM5i7DGB"), tsize: 23319629, hasTsize: true},
{name: "chat.txt", hasName: true, hash: mkcid(t, "QmNVrxbB25cKTRuKg2DuhUmBVEK9NmCwWEHtsHPV6YutHw"), tsize: 996, hasTsize: true},
{name: "playback.m3u", hasName: true, hash: mkcid(t, "QmUcjKzDLXBPmB6BKHeKSh6ZoFZjss4XDhMRdLYRVuvVfu"), tsize: 116, hasTsize: true},
{name: "zoom_0.mp4", hasName: true, hash: mkcid(t, "QmQqy2SiEkKgr2cw5UbQ93TtLKEMsD8TdcWggR8q9JabjX"), tsize: 306281879, hasTsize: true},
}
runTest(
t,
"12390a221220b4397c02da5513563d33eef894bf68f2ccdf1bdfc14a976956ab3d1c72f735a0120e617564696f5f6f6e6c792e6d346118cda88f0b12310a221220025c13fcd1a885df444f64a4a82a26aea867b1148c68cb671e83589f971149321208636861742e74787418e40712340a2212205d44a305b9b328ab80451d0daa72a12a7bf2763c5f8bbe327597a31ee40d1e48120c706c61796261636b2e6d3375187412360a2212202539ed6e85f2a6f9097db9d76cffd49bf3042eb2e3e8e9af4a3ce842d49dea22120a7a6f6f6d5f302e6d70341897fb8592010a020801",
expected)
}
func TestNodeAlternativeOrder(t *testing.T) {
// This input has Data before Links.
input, err := hex.DecodeString("0a040802180612240a221220cf92fdefcdc34cac009c8b05eb662be0618db9de55ecd42785e9ec6712f8df6512240a221220cf92fdefcdc34cac009c8b05eb662be0618db9de55ecd42785e9ec6712f8df65")
if err != nil {
t.Fatal(err)
}
nb := Type.PBNode.NewBuilder()
if err := DecodeBytes(nb, input); err != nil {
t.Fatal(err)
}
node := nb.Build()
// We don't really care what the node looks like, or what the exact
// re-encode bytes are. But we do care that it's not exactly the same,
// but still the same length.
output, err := AppendEncode(nil, node)
if err != nil {
t.Fatal(err)
}
if bytes.Equal(input, output) {
t.Fatal("re-encoding should use canonical PBNode field order")
}
if len(input) != len(output) {
t.Fatal("re-encoding should have the same number of bytes")
}
}
func TestNodeWithDataBetweenLinks(t *testing.T) {
// This input has one Links element, then Data, then another Links element.
// As per the spec, this should fail as a duplicate Links field.
input, err := hex.DecodeString("12240a221220cf92fdefcdc34cac009c8b05eb662be0618db9de55ecd42785e9ec6712f8df650a040802180612240a221220cf92fdefcdc34cac009c8b05eb662be0618db9de55ecd42785e9ec6712f8df65")
if err != nil {
t.Fatal(err)
}
nb := Type.PBNode.NewBuilder()
if err := DecodeBytes(nb, input); err == nil {
t.Fatal("expected Decode to fail")
}
}
package dagpb
// mirrored in JavaScript @ https://github.com/ipld/js-dag-pb/blob/master/test/test-compat.js
import (
"bytes"
"encoding/hex"
"encoding/json"
"strings"
"testing"
cid "github.com/ipfs/go-cid"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/fluent"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
basicnode "github.com/ipld/go-ipld-prime/node/basic"
)
var dataZero []byte = make([]byte, 0)
var dataSome []byte = []byte{0, 1, 2, 3, 4}
var acid cid.Cid = _mkcid()
var zeroName string = ""
var someName string = "some name"
var zeroTsize uint64 = 0
var someTsize uint64 = 1010
var largeTsize uint64 = 9007199254740991 // JavaScript Number.MAX_SAFE_INTEGER
type testCase struct {
name string
node *pbNode
expectedBytes string
expectedForm string
encodeError string
decodeError string
}
var testCases = []testCase{
{
name: "empty",
node: &pbNode{},
expectedBytes: "",
expectedForm: `{
"Links": []
}`,
encodeError: "missing required fields: Links",
},
{
name: "Data zero",
node: &pbNode{data: dataZero},
expectedBytes: "0a00",
expectedForm: `{
"Data": "",
"Links": []
}`,
encodeError: "missing required fields: Links",
},
{
name: "Data some",
node: &pbNode{data: dataSome},
expectedBytes: "0a050001020304",
expectedForm: `{
"Data": "0001020304",
"Links": []
}`,
encodeError: "missing required fields: Links",
},
{
name: "Links zero",
node: &pbNode{links: []pbLink{}},
expectedBytes: "",
expectedForm: `{
"Links": []
}`,
},
{
name: "Data some Links zero",
node: &pbNode{data: dataSome, links: []pbLink{}},
expectedBytes: "0a050001020304",
expectedForm: `{
"Data": "0001020304",
"Links": []
}`,
},
{
name: "Links empty",
node: &pbNode{links: []pbLink{{}}},
expectedBytes: "1200",
encodeError: "missing required fields: Hash",
decodeError: "expected CID",
},
{
name: "Data some Links empty",
node: &pbNode{data: dataSome, links: []pbLink{{}}},
expectedBytes: "12000a050001020304",
encodeError: "missing required fields: Hash",
decodeError: "expected CID",
},
{
name: "Links Hash zero",
expectedBytes: "12020a00",
decodeError: "expected CID", // error should come up from go-cid too
},
{
name: "Links Hash some",
node: &pbNode{links: []pbLink{{hash: acid}}},
expectedBytes: "120b0a09015500050001020304",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304"
}
]
}`,
},
{
name: "Links Name zero",
node: &pbNode{links: []pbLink{{name: zeroName, hasName: true}}},
expectedBytes: "12021200",
encodeError: "missing required fields: Hash",
decodeError: "expected CID",
},
{
name: "Links Hash some Name zero",
node: &pbNode{links: []pbLink{{hash: acid, name: zeroName, hasName: true}}},
expectedBytes: "120d0a090155000500010203041200",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304",
"Name": ""
}
]
}`,
},
{
name: "Links Name some",
node: &pbNode{links: []pbLink{{name: someName, hasName: true}}},
expectedBytes: "120b1209736f6d65206e616d65",
encodeError: "missing required fields: Hash",
decodeError: "expected CID",
},
{
name: "Links Hash some Name some",
node: &pbNode{links: []pbLink{{hash: acid, name: someName, hasName: true}}},
expectedBytes: "12160a090155000500010203041209736f6d65206e616d65",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304",
"Name": "some name"
}
]
}`,
},
{
name: "Links Tsize zero",
node: &pbNode{links: []pbLink{{tsize: zeroTsize, hasTsize: true}}},
expectedBytes: "12021800",
encodeError: "missing required fields: Hash",
decodeError: "expected CID",
},
{
name: "Links Hash some Tsize zero",
node: &pbNode{links: []pbLink{{hash: acid, tsize: zeroTsize, hasTsize: true}}},
expectedBytes: "120d0a090155000500010203041800",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304",
"Tsize": 0
}
]
}`,
},
{
name: "Links Tsize some",
node: &pbNode{links: []pbLink{{tsize: someTsize, hasTsize: true}}},
expectedBytes: "120318f207",
encodeError: "missing required fields: Hash",
decodeError: "expected CID",
},
{
name: "Links Hash some Tsize some",
node: &pbNode{links: []pbLink{{hash: acid, tsize: largeTsize, hasTsize: true}}},
expectedBytes: "12140a0901550005000102030418ffffffffffffff0f",
expectedForm: `{
"Links": [
{
"Hash": "015500050001020304",
"Tsize": 9007199254740991
}
]
}`,
},
}
func TestCompat(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
verifyRoundTrip(t, tc)
})
}
}
func verifyRoundTrip(t *testing.T, tc testCase) {
var err error
var actualBytes string
var actualForm string
if tc.node != nil {
node := buildNode(*tc.node)
actualBytes, err = nodeToString(t, node)
if tc.encodeError != "" {
if err != nil {
if !strings.Contains(err.Error(), tc.encodeError) {
t.Fatalf("got unexpeced encode error: [%v] (expected [%v])", err.Error(), tc.encodeError)
}
} else {
t.Fatalf("did not get expected encode error: %v", tc.encodeError)
}
} else {
if err != nil {
t.Fatal(err)
} else {
if actualBytes != tc.expectedBytes {
t.Logf(
"Expected bytes: [%v]\nGot: [%v]\n",
tc.expectedBytes,
actualBytes)
t.Error("Did not match")
}
}
}
}
actualForm, err = bytesToFormString(t, tc.expectedBytes, basicnode.Prototype__Map{}.NewBuilder())
if tc.decodeError != "" {
if err != nil {
if !strings.Contains(err.Error(), tc.decodeError) {
t.Fatalf("got unexpeced decode error: [%v] (expected [%v])", err.Error(), tc.decodeError)
}
} else {
t.Fatalf("did not get expected decode error: %v", tc.decodeError)
}
} else {
if err != nil {
t.Fatal(err)
}
if actualForm != tc.expectedForm {
t.Logf(
"Expected form: [%v]\nGot: [%v]\n",
tc.expectedForm,
actualForm)
t.Error("Did not match")
}
}
}
func buildNode(n pbNode) ipld.Node {
return fluent.MustBuildMap(basicnode.Prototype__Map{}, 2, func(fma fluent.MapAssembler) {
if n.data != nil {
fma.AssembleEntry("Data").AssignBytes(n.data)
}
if n.links != nil {
fma.AssembleEntry("Links").CreateList(int64(len(n.links)), func(fla fluent.ListAssembler) {
for _, link := range n.links {
fla.AssembleValue().CreateMap(3, func(fma fluent.MapAssembler) {
if link.hasName {
fma.AssembleEntry("Name").AssignString(link.name)
}
if link.hasTsize {
fma.AssembleEntry("Tsize").AssignInt(int64(link.tsize))
}
if link.hash.ByteLen() != 0 {
fma.AssembleEntry("Hash").AssignLink(cidlink.Link{Cid: link.hash})
}
})
}
})
}
})
}
func nodeToString(t *testing.T, node ipld.Node) (string, error) {
var buf bytes.Buffer
err := Marshal(node, &buf)
if err != nil {
return "", err
}
h := hex.EncodeToString(buf.Bytes())
t.Logf("[%v]\n", h)
return h, nil
}
func bytesToFormString(t *testing.T, bytesHex string, nb ipld.NodeBuilder) (string, error) {
byts, err := hex.DecodeString(bytesHex)
if err != nil {
return "", err
}
if err = Unmarshal(nb, bytes.NewReader(byts)); err != nil {
return "", err
}
node := nb.Build()
str, err := json.MarshalIndent(cleanPBNode(t, node), "", "\t")
if err != nil {
return "", err
}
return string(str), nil
}
// convert a ipld.Node (PBLink) into a map for clean JSON marshalling
func cleanPBLink(t *testing.T, link ipld.Node) map[string]interface{} {
if link == nil {
return nil
}
nl := make(map[string]interface{})
hash, _ := link.LookupByString("Hash")
if hash != nil {
l, _ := hash.AsLink()
cl, _ := l.(cidlink.Link)
nl["Hash"] = hex.EncodeToString(cl.Bytes())
}
name, _ := link.LookupByString("Name")
if name != nil {
name, _ := name.AsString()
nl["Name"] = name
}
tsize, _ := link.LookupByString("Tsize")
if tsize != nil {
tsize, _ := tsize.AsInt()
nl["Tsize"] = tsize
}
return nl
}
// convert an ipld.Node (PBNode) into a map for clean JSON marshalling
func cleanPBNode(t *testing.T, node ipld.Node) map[string]interface{} {
nn := make(map[string]interface{})
data, _ := node.LookupByString("Data")
if data != nil {
byts, _ := data.AsBytes()
nn["Data"] = hex.EncodeToString(byts)
}
links, _ := node.LookupByString("Links")
if links != nil {
linksList := make([]map[string]interface{}, links.Length())
linksIter := links.ListIterator()
for !linksIter.Done() {
ii, link, _ := linksIter.Next()
linksList[ii] = cleanPBLink(t, link)
}
nn["Links"] = linksList
}
return nn
}
func _mkcid() cid.Cid {
_, c, _ := cid.CidFromBytes([]byte{1, 85, 0, 5, 0, 1, 2, 3, 4})
return c
}
/*
Package dagpb provides an implementation of the IPLD DAG-PB spec
(https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-pb.md) for
go-ipld-prime (https://github.com/ipld/go-ipld-prime/).
Use Decode() and Encode() directly, or import this package to have this codec
registered into the go-ipld-prime multicodec registry and available from the
cidlink.DefaultLinkSystem.
Nodes encoded with this codec _must_ conform to the DAG-PB spec. Specifically,
they should have the non-optional fields shown in the DAG-PB schema:
type PBNode struct {
Links [PBLink]
Data optional Bytes
}
type PBLink struct {
Hash Link
Name optional String
Tsize optional Int
}
Use dagpb.Type.PBNode and friends directly for strictness guarantees. Basic
ipld.Node's will need to have the appropriate fields (and no others) to
successfully encode using this codec.
*/
package dagpb
//go:generate go run gen.go
//go:generate gofmt -w ipldsch_minima.go ipldsch_satisfaction.go ipldsch_types.go
//go:build ignore
// +build ignore
package main
// based on https://github.com/ipld/go-ipld-prime-proto/blob/master/gen/main.go
import (
"fmt"
"os"
"github.com/ipld/go-ipld-prime/schema"
gengo "github.com/ipld/go-ipld-prime/schema/gen/go"
)
func main() {
ts := schema.TypeSystem{}
ts.Init()
adjCfg := &gengo.AdjunctCfg{}
pkgName := "dagpb"
ts.Accumulate(schema.SpawnString("String"))
ts.Accumulate(schema.SpawnInt("Int"))
ts.Accumulate(schema.SpawnLink("Link"))
ts.Accumulate(schema.SpawnBytes("Bytes"))
/*
type PBLink struct {
Hash Link
Name optional String
Tsize optional Int
}
*/
ts.Accumulate(schema.SpawnStruct("PBLink",
[]schema.StructField{
schema.SpawnStructField("Hash", "Link", false, false),
schema.SpawnStructField("Name", "String", true, false),
schema.SpawnStructField("Tsize", "Int", true, false),
},
schema.SpawnStructRepresentationMap(nil),
))
ts.Accumulate(schema.SpawnList("PBLinks", "PBLink", false))
/*
type PBNode struct {
Links [PBLink]
Data optional Bytes
}
*/
ts.Accumulate(schema.SpawnStruct("PBNode",
[]schema.StructField{
schema.SpawnStructField("Links", "PBLinks", false, false),
schema.SpawnStructField("Data", "Bytes", true, false),
},
schema.SpawnStructRepresentationMap(nil),
))
if errs := ts.ValidateGraph(); errs != nil {
for _, err := range errs {
fmt.Printf("- %s\n", err)
}
os.Exit(1)
}
gengo.Generate(".", pkgName, ts, adjCfg)
}
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/ipfs/go-cid v0.0.4/go.mod h1:4LLaPOQwmk5z9LBgQnpkivrx8BJjUyGwTXCd5Xfj6+M=
github.com/ipfs/go-cid v0.0.7 h1:ysQJVJA3fNDF1qigJbsSQOdjhVLsOEoPdh0+R97k3jY=
github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
github.com/ipld/go-ipld-prime v0.11.0 h1:jD/b/22R7CSL+F9xNffcexs+wO0Ji/TfwXO/TWck+70=
github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHtEaLglS3ZeV8=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/klauspost/cpuid/v2 v2.0.4 h1:g0I61F2K2DjRHz1cnxlkNSBIaePVoJIjjnHui8QHbiw=
github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 h1:lYpkrQH5ajf0OXOcUbGjvZxxijuBwbbmlSxLiuofa+g=
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ=
github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM=
github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g=
github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM=
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=
github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4=
github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM=
github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs=
github.com/multiformats/go-multibase v0.0.3 h1:l/B6bJDQjvQ5G52jw4QGSYeOTZoAwIO77RblWplfIqk=
github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc=
github.com/multiformats/go-multihash v0.0.10/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=
github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc=
github.com/multiformats/go-multihash v0.0.15 h1:hWOPdrNqDjwHDx82vsYGSDZNyktOJJ2dzZJzFkOV1jM=
github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg=
github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY=
github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE=
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e h1:ZOcivgkkFRnjfoTcGsDq3UQYiBmekwLA+qg0OjyB/ls=
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e/go.mod h1:uIp+gprXxxrWSjjklXD+mN4wed/tMfjMMmN/9+JsA9o=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a h1:G++j5e0OC488te356JvdhaM8YS6nMsjLAYF7JxCv07w=
github.com/warpfork/go-wish v0.0.0-20200122115046-b9ea61034e4a/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2 h1:46ULzRKLh1CwgRq2dC5SlBzEqqNCi8rreOZnNrbqcIY=
golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
package dagpb
// Code generated by go-ipld-prime gengo. DO NOT EDIT.
import (
"fmt"
"github.com/ipld/go-ipld-prime"
"github.com/ipld/go-ipld-prime/schema"
)
const (
midvalue = schema.Maybe(4)
allowNull = schema.Maybe(5)
)
type maState uint8
const (
maState_initial maState = iota
maState_midKey
maState_expectValue
maState_midValue
maState_finished
)
type laState uint8
const (
laState_initial laState = iota
laState_midValue
laState_finished
)
type _ErrorThunkAssembler struct {
e error
}
func (ea _ErrorThunkAssembler) BeginMap(_ int64) (ipld.MapAssembler, error) { return nil, ea.e }
func (ea _ErrorThunkAssembler) BeginList(_ int64) (ipld.ListAssembler, error) { return nil, ea.e }
func (ea _ErrorThunkAssembler) AssignNull() error { return ea.e }
func (ea _ErrorThunkAssembler) AssignBool(bool) error { return ea.e }
func (ea _ErrorThunkAssembler) AssignInt(int64) error { return ea.e }
func (ea _ErrorThunkAssembler) AssignFloat(float64) error { return ea.e }
func (ea _ErrorThunkAssembler) AssignString(string) error { return ea.e }
func (ea _ErrorThunkAssembler) AssignBytes([]byte) error { return ea.e }
func (ea _ErrorThunkAssembler) AssignLink(ipld.Link) error { return ea.e }
func (ea _ErrorThunkAssembler) AssignNode(ipld.Node) error { return ea.e }
func (ea _ErrorThunkAssembler) Prototype() ipld.NodePrototype {
panic(fmt.Errorf("cannot get prototype from error-carrying assembler: already derailed with error: %w", ea.e))
}
This diff is collapsed.
package dagpb
// Code generated by go-ipld-prime gengo. DO NOT EDIT.
import (
ipld "github.com/ipld/go-ipld-prime"
)
var _ ipld.Node = nil // suppress errors when this dependency is not referenced
// Type is a struct embeding a NodePrototype/Type for every Node implementation in this package.
// One of its major uses is to start the construction of a value.
// You can use it like this:
//
// dagpb.Type.YourTypeName.NewBuilder().BeginMap() //...
//
// and:
//
// dagpb.Type.OtherTypeName.NewBuilder().AssignString("x") // ...
//
var Type typeSlab
type typeSlab struct {
Bytes _Bytes__Prototype
Bytes__Repr _Bytes__ReprPrototype
Int _Int__Prototype
Int__Repr _Int__ReprPrototype
Link _Link__Prototype
Link__Repr _Link__ReprPrototype
PBLink _PBLink__Prototype
PBLink__Repr _PBLink__ReprPrototype
PBLinks _PBLinks__Prototype
PBLinks__Repr _PBLinks__ReprPrototype
PBNode _PBNode__Prototype
PBNode__Repr _PBNode__ReprPrototype
String _String__Prototype
String__Repr _String__ReprPrototype
}
// --- type definitions follow ---
// Bytes matches the IPLD Schema type "Bytes". It has bytes kind.
type Bytes = *_Bytes
type _Bytes struct{ x []byte }
// Int matches the IPLD Schema type "Int". It has int kind.
type Int = *_Int
type _Int struct{ x int64 }
// Link matches the IPLD Schema type "Link". It has link kind.
type Link = *_Link
type _Link struct{ x ipld.Link }
// PBLink matches the IPLD Schema type "PBLink". It has Struct type-kind, and may be interrogated like map kind.
type PBLink = *_PBLink
type _PBLink struct {
Hash _Link
Name _String__Maybe
Tsize _Int__Maybe
}
// PBLinks matches the IPLD Schema type "PBLinks". It has list kind.
type PBLinks = *_PBLinks
type _PBLinks struct {
x []_PBLink
}
// PBNode matches the IPLD Schema type "PBNode". It has Struct type-kind, and may be interrogated like map kind.
type PBNode = *_PBNode
type _PBNode struct {
Links _PBLinks
Data _Bytes__Maybe
}
// String matches the IPLD Schema type "String". It has string kind.
type String = *_String
type _String struct{ x string }
package dagpb
import (
"fmt"
"io"
"sort"
"github.com/ipfs/go-cid"
ipld "github.com/ipld/go-ipld-prime"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"google.golang.org/protobuf/encoding/protowire"
)
type pbLink struct {
hash cid.Cid
name string
hasName bool
tsize uint64
hasTsize bool
}
// Encode provides an IPLD codec encode interface for DAG-PB data. Provide a
// conforming Node and a destination for bytes to marshal a DAG-PB IPLD Node.
// The Node must strictly conform to the DAG-PB schema
// (https://github.com/ipld/specs/blob/master/block-layer/codecs/dag-pb.md).
// For safest use, build Nodes using the Type.PBNode type.
// This function is registered via the go-ipld-prime link loader for multicodec
// code 0x70 when this package is invoked via init.
func Encode(node ipld.Node, w io.Writer) error {
// 1KiB can be allocated on the stack, and covers most small nodes
// without having to grow the buffer and cause allocations.
enc := make([]byte, 0, 1024)
enc, err := AppendEncode(enc, node)
if err != nil {
return err
}
_, err = w.Write(enc)
return err
}
// AppendEncode is like Encode, but it uses a destination buffer directly.
// This means less copying of bytes, and if the destination has enough capacity,
// fewer allocations.
func AppendEncode(enc []byte, inNode ipld.Node) ([]byte, error) {
// Wrap in a typed node for some basic schema form checking
builder := Type.PBNode.NewBuilder()
if err := builder.AssignNode(inNode); err != nil {
return enc, err
}
node := builder.Build()
links, err := node.LookupByString("Links")
if err != nil {
return enc, err
}
if links.Length() > 0 {
// collect links into a slice so we can properly sort for encoding
pbLinks := make([]pbLink, links.Length())
linksIter := links.ListIterator()
for !linksIter.Done() {
ii, link, err := linksIter.Next()
if err != nil {
return enc, err
}
{ // Hash (required)
d, err := link.LookupByString("Hash")
if err != nil {
return enc, err
}
l, err := d.AsLink()
if err != nil {
return enc, err
}
if err != nil {
return enc, err
}
cl, ok := l.(cidlink.Link)
if !ok {
// this _should_ be taken care of by the Typed conversion above with
// "missing required fields: Hash"
return enc, fmt.Errorf("invalid DAG-PB form (link must have a Hash)")
}
pbLinks[ii].hash = cl.Cid
}
{ // Name (optional)
nameNode, err := link.LookupByString("Name")
if err != nil {
return enc, err
}
if !nameNode.IsAbsent() {
name, err := nameNode.AsString()
if err != nil {
return enc, err
}
pbLinks[ii].name = name
pbLinks[ii].hasName = true
}
}
{ // Tsize (optional)
tsizeNode, err := link.LookupByString("Tsize")
if err != nil {
return enc, err
}
if !tsizeNode.IsAbsent() {
tsize, err := tsizeNode.AsInt()
if err != nil {
return enc, err
}
if tsize < 0 {
return enc, fmt.Errorf("Link has negative Tsize value [%v]", tsize)
}
utsize := uint64(tsize)
pbLinks[ii].tsize = utsize
pbLinks[ii].hasTsize = true
}
}
} // for
// links must be strictly sorted by Name before encoding, leaving stable
// ordering where the names are the same (or absent)
sort.Stable(pbLinkSlice(pbLinks))
for _, link := range pbLinks {
hash := link.hash.Bytes()
size := 0
size += protowire.SizeTag(2)
size += protowire.SizeBytes(len(hash))
if link.hasName {
size += protowire.SizeTag(2)
size += protowire.SizeBytes(len(link.name))
}
if link.hasTsize {
size += protowire.SizeTag(3)
size += protowire.SizeVarint(uint64(link.tsize))
}
enc = protowire.AppendTag(enc, 2, 2) // field & wire type for Links
enc = protowire.AppendVarint(enc, uint64(size))
enc = protowire.AppendTag(enc, 1, 2) // field & wire type for Hash
enc = protowire.AppendBytes(enc, hash)
if link.hasName {
enc = protowire.AppendTag(enc, 2, 2) // field & wire type for Name
enc = protowire.AppendString(enc, link.name)
}
if link.hasTsize {
enc = protowire.AppendTag(enc, 3, 0) // field & wire type for Tsize
enc = protowire.AppendVarint(enc, uint64(link.tsize))
}
}
} // if links
// Data (optional)
data, err := node.LookupByString("Data")
if err != nil {
return enc, err
}
if !data.IsAbsent() {
byts, err := data.AsBytes()
if err != nil {
return enc, err
}
enc = protowire.AppendTag(enc, 1, 2) // field & wire type for Data
enc = protowire.AppendBytes(enc, byts)
}
return enc, err
}
type pbLinkSlice []pbLink
func (ls pbLinkSlice) Len() int { return len(ls) }
func (ls pbLinkSlice) Swap(a, b int) { ls[a], ls[b] = ls[b], ls[a] }
func (ls pbLinkSlice) Less(a, b int) bool { return pbLinkLess(ls[a], ls[b]) }
func pbLinkLess(a pbLink, b pbLink) bool {
return a.name < b.name
}
package dagpb
import (
"io"
ipld "github.com/ipld/go-ipld-prime"
cidlink "github.com/ipld/go-ipld-prime/linking/cid"
"github.com/ipld/go-ipld-prime/multicodec"
"github.com/ipld/go-ipld-prime/traversal"
)
var (
_ ipld.Decoder = Decode
_ ipld.Encoder = Encode
)
func init() {
multicodec.RegisterDecoder(0x70, Decode)
multicodec.RegisterEncoder(0x70, Encode)
}
// AddSupportToChooser takes an existing node prototype chooser and subs in
// PBNode for the dag-pb multicodec code.
func AddSupportToChooser(existing traversal.LinkTargetNodePrototypeChooser) traversal.LinkTargetNodePrototypeChooser {
return func(lnk ipld.Link, lnkCtx ipld.LinkContext) (ipld.NodePrototype, error) {
if lnk, ok := lnk.(cidlink.Link); ok && lnk.Cid.Prefix().Codec == 0x70 {
return Type.PBNode, nil
}
return existing(lnk, lnkCtx)
}
}
// We switched to simpler API names after v1.0.0, so keep the old names around
// as deprecated forwarding funcs until a future v2+.
// TODO: consider deprecating Marshal/Unmarshal too, since it's a bit
// unnecessary to have two supported names for each API.
// Deprecated: use Decode instead.
func Decoder(na ipld.NodeAssembler, r io.Reader) error { return Decode(na, r) }
// Deprecated: use Decode instead.
func Unmarshal(na ipld.NodeAssembler, r io.Reader) error { return Decode(na, r) }
// Deprecated: use Encode instead.
func Encoder(inNode ipld.Node, w io.Writer) error { return Encode(inNode, w) }
// Deprecated: use Encode instead.
func Marshal(inNode ipld.Node, w io.Writer) error { return Encode(inNode, w) }
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment