├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ └── open_an_issue.md ├── config.yml └── workflows │ ├── automerge.yml │ ├── go-check.yml │ ├── go-test.yml │ ├── release-check.yml │ ├── releaser.yml │ ├── stale.yml │ └── tagpush.yml ├── .gx ├── lastpubver └── post-install ├── LICENSE ├── README.md ├── blockservice.go ├── blockservice_test.go ├── go.mod ├── go.sum ├── internal └── tracing.go ├── test ├── blocks_test.go └── mock.go └── version.json /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Getting Help on IPFS 4 | url: https://ipfs.io/help 5 | about: All information about how and where to get help on IPFS. 6 | - name: IPFS Official Forum 7 | url: https://discuss.ipfs.io 8 | about: Please post general questions, support requests, and discussions here. 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/open_an_issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Open an issue 3 | about: Only for actionable issues relevant to this repository. 4 | title: '' 5 | labels: need/triage 6 | assignees: '' 7 | 8 | --- 9 | 20 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | # Configuration for welcome - https://github.com/behaviorbot/welcome 2 | 3 | # Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome 4 | # Comment to be posted to on first time issues 5 | newIssueWelcomeComment: > 6 | Thank you for submitting your first issue to this repository! A maintainer 7 | will be here shortly to triage and review. 8 | 9 | In the meantime, please double-check that you have provided all the 10 | necessary information to make this process easy! Any information that can 11 | help save additional round trips is useful! We currently aim to give 12 | initial feedback within **two business days**. If this does not happen, feel 13 | free to leave a comment. 14 | 15 | Please keep an eye on how this issue will be labeled, as labels give an 16 | overview of priorities, assignments and additional actions requested by the 17 | maintainers: 18 | 19 | - "Priority" labels will show how urgent this is for the team. 20 | - "Status" labels will show if this is ready to be worked on, blocked, or in progress. 21 | - "Need" labels will indicate if additional input or analysis is required. 22 | 23 | Finally, remember to use https://discuss.ipfs.io if you just need general 24 | support. 25 | 26 | # Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome 27 | # Comment to be posted to on PRs from first time contributors in your repository 28 | newPRWelcomeComment: > 29 | Thank you for submitting this PR! 30 | 31 | A maintainer will be here shortly to review it. 32 | 33 | We are super grateful, but we are also overloaded! Help us by making sure 34 | that: 35 | 36 | * The context for this PR is clear, with relevant discussion, decisions 37 | and stakeholders linked/mentioned. 38 | 39 | * Your contribution itself is clear (code comments, self-review for the 40 | rest) and in its best form. Follow the [code contribution 41 | guidelines](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md#code-contribution-guidelines) 42 | if they apply. 43 | 44 | Getting other community members to do a review would be great help too on 45 | complex PRs (you can ask in the chats/forums). If you are unsure about 46 | something, just leave us a comment. 47 | 48 | Next steps: 49 | 50 | * A maintainer will triage and assign priority to this PR, commenting on 51 | any missing things and potentially assigning a reviewer for high 52 | priority items. 53 | 54 | * The PR gets reviews, discussed and approvals as needed. 55 | 56 | * The PR is merged by maintainers when it has been approved and comments addressed. 57 | 58 | We currently aim to provide initial feedback/triaging within **two business 59 | days**. Please keep an eye on any labelling actions, as these will indicate 60 | priorities and status of your contribution. 61 | 62 | We are very grateful for your contribution! 63 | 64 | 65 | # Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge 66 | # Comment to be posted to on pull requests merged by a first time user 67 | # Currently disabled 68 | #firstPRMergeComment: "" 69 | -------------------------------------------------------------------------------- /.github/workflows/automerge.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | name: Automerge 5 | on: [ pull_request ] 6 | 7 | jobs: 8 | automerge: 9 | uses: protocol/.github/.github/workflows/automerge.yml@master 10 | with: 11 | job: 'automerge' 12 | -------------------------------------------------------------------------------- /.github/workflows/go-check.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | on: [push, pull_request] 5 | name: Go Checks 6 | 7 | jobs: 8 | unit: 9 | runs-on: ubuntu-latest 10 | name: All 11 | steps: 12 | - uses: actions/checkout@v3 13 | with: 14 | submodules: recursive 15 | - id: config 16 | uses: protocol/.github/.github/actions/read-config@master 17 | - uses: actions/setup-go@v3 18 | with: 19 | go-version: 1.20.x 20 | - name: Run repo-specific setup 21 | uses: ./.github/actions/go-check-setup 22 | if: hashFiles('./.github/actions/go-check-setup') != '' 23 | - name: Install staticcheck 24 | run: go install honnef.co/go/tools/cmd/staticcheck@4970552d932f48b71485287748246cf3237cebdf # 2023.1 (v0.4.0) 25 | - name: Check that go.mod is tidy 26 | uses: protocol/multiple-go-modules@v1.2 27 | with: 28 | run: | 29 | go mod tidy 30 | if [[ -n $(git ls-files --other --exclude-standard --directory -- go.sum) ]]; then 31 | echo "go.sum was added by go mod tidy" 32 | exit 1 33 | fi 34 | git diff --exit-code -- go.sum go.mod 35 | - name: gofmt 36 | if: success() || failure() # run this step even if the previous one failed 37 | run: | 38 | out=$(gofmt -s -l .) 39 | if [[ -n "$out" ]]; then 40 | echo $out | awk '{print "::error file=" $0 ",line=0,col=0::File is not gofmt-ed."}' 41 | exit 1 42 | fi 43 | - name: go vet 44 | if: success() || failure() # run this step even if the previous one failed 45 | uses: protocol/multiple-go-modules@v1.2 46 | with: 47 | run: go vet ./... 48 | - name: staticcheck 49 | if: success() || failure() # run this step even if the previous one failed 50 | uses: protocol/multiple-go-modules@v1.2 51 | with: 52 | run: | 53 | set -o pipefail 54 | staticcheck ./... | sed -e 's@\(.*\)\.go@./\1.go@g' 55 | - name: go generate 56 | uses: protocol/multiple-go-modules@v1.2 57 | if: (success() || failure()) && fromJSON(steps.config.outputs.json).gogenerate == true 58 | with: 59 | run: | 60 | git clean -fd # make sure there aren't untracked files / directories 61 | go generate -x ./... 62 | # check if go generate modified or added any files 63 | if ! $(git add . && git diff-index HEAD --exit-code --quiet); then 64 | echo "go generated caused changes to the repository:" 65 | git status --short 66 | exit 1 67 | fi 68 | -------------------------------------------------------------------------------- /.github/workflows/go-test.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | on: [push, pull_request] 5 | name: Go Test 6 | 7 | jobs: 8 | unit: 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | os: [ "ubuntu", "windows", "macos" ] 13 | go: ["1.19.x","1.20.x"] 14 | env: 15 | COVERAGES: "" 16 | runs-on: ${{ fromJSON(vars[format('UCI_GO_TEST_RUNNER_{0}', matrix.os)] || format('"{0}-latest"', matrix.os)) }} 17 | name: ${{ matrix.os }} (go ${{ matrix.go }}) 18 | steps: 19 | - uses: actions/checkout@v3 20 | with: 21 | submodules: recursive 22 | - id: config 23 | uses: protocol/.github/.github/actions/read-config@master 24 | - uses: actions/setup-go@v3 25 | with: 26 | go-version: ${{ matrix.go }} 27 | - name: Go information 28 | run: | 29 | go version 30 | go env 31 | - name: Use msys2 on windows 32 | if: matrix.os == 'windows' 33 | shell: bash 34 | # The executable for msys2 is also called bash.cmd 35 | # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#shells 36 | # If we prepend its location to the PATH 37 | # subsequent 'shell: bash' steps will use msys2 instead of gitbash 38 | run: echo "C:/msys64/usr/bin" >> $GITHUB_PATH 39 | - name: Run repo-specific setup 40 | uses: ./.github/actions/go-test-setup 41 | if: hashFiles('./.github/actions/go-test-setup') != '' 42 | - name: Run tests 43 | if: contains(fromJSON(steps.config.outputs.json).skipOSes, matrix.os) == false 44 | uses: protocol/multiple-go-modules@v1.2 45 | with: 46 | # Use -coverpkg=./..., so that we include cross-package coverage. 47 | # If package ./A imports ./B, and ./A's tests also cover ./B, 48 | # this means ./B's coverage will be significantly higher than 0%. 49 | run: go test -v -shuffle=on -coverprofile=module-coverage.txt -coverpkg=./... ./... 50 | - name: Run tests (32 bit) 51 | # can't run 32 bit tests on OSX. 52 | if: matrix.os != 'macos' && 53 | fromJSON(steps.config.outputs.json).skip32bit != true && 54 | contains(fromJSON(steps.config.outputs.json).skipOSes, matrix.os) == false 55 | uses: protocol/multiple-go-modules@v1.2 56 | env: 57 | GOARCH: 386 58 | with: 59 | run: | 60 | export "PATH=$PATH_386:$PATH" 61 | go test -v -shuffle=on ./... 62 | - name: Run tests with race detector 63 | # speed things up. Windows and OSX VMs are slow 64 | if: matrix.os == 'ubuntu' && 65 | contains(fromJSON(steps.config.outputs.json).skipOSes, matrix.os) == false 66 | uses: protocol/multiple-go-modules@v1.2 67 | with: 68 | run: go test -v -race ./... 69 | - name: Collect coverage files 70 | shell: bash 71 | run: echo "COVERAGES=$(find . -type f -name 'module-coverage.txt' | tr -s '\n' ',' | sed 's/,$//')" >> $GITHUB_ENV 72 | - name: Upload coverage to Codecov 73 | uses: codecov/codecov-action@d9f34f8cd5cb3b3eb79b3e4b5dae3a16df499a70 # v3.1.1 74 | with: 75 | files: '${{ env.COVERAGES }}' 76 | env_vars: OS=${{ matrix.os }}, GO=${{ matrix.go }} 77 | -------------------------------------------------------------------------------- /.github/workflows/release-check.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | name: Release Checker 5 | on: 6 | pull_request_target: 7 | paths: [ 'version.json' ] 8 | 9 | jobs: 10 | release-check: 11 | uses: protocol/.github/.github/workflows/release-check.yml@master 12 | with: 13 | go-version: 1.20.x 14 | -------------------------------------------------------------------------------- /.github/workflows/releaser.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | name: Releaser 5 | on: 6 | push: 7 | paths: [ 'version.json' ] 8 | 9 | jobs: 10 | releaser: 11 | uses: protocol/.github/.github/workflows/releaser.yml@master 12 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Close and mark stale issue 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' 6 | 7 | jobs: 8 | stale: 9 | uses: pl-strflt/.github/.github/workflows/reusable-stale-issue.yml@v0.3 10 | -------------------------------------------------------------------------------- /.github/workflows/tagpush.yml: -------------------------------------------------------------------------------- 1 | # File managed by web3-bot. DO NOT EDIT. 2 | # See https://github.com/protocol/.github/ for details. 3 | 4 | name: Tag Push Checker 5 | on: 6 | push: 7 | tags: 8 | - v* 9 | 10 | jobs: 11 | releaser: 12 | uses: protocol/.github/.github/workflows/tagpush.yml@master 13 | -------------------------------------------------------------------------------- /.gx/lastpubver: -------------------------------------------------------------------------------- 1 | 1.1.31: QmTRbLgKn2BKNvr9z5JQ3uZC4FSyLkad9t7qTVPkbH1LRB 2 | -------------------------------------------------------------------------------- /.gx/post-install: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipfs/go-blockservice/0a3b4941053a2b38977a52e62c1279c4e945f8bb/.gx/post-install -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2018 Juan Batiz-Benet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | go-blockservice 2 | ================== 3 | 4 | > go-blockservice provides a seamless interface to both local and remote storage backends. 5 | 6 | [![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) 7 | [![](https://img.shields.io/badge/project-IPFS-blue.svg?style=flat-square)](http://ipfs.io/) 8 | [![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs) 9 | [![Coverage Status](https://codecov.io/gh/ipfs/go-block-format/branch/master/graph/badge.svg)](https://codecov.io/gh/ipfs/go-block-format/branch/master) 10 | [![Build Status](https://circleci.com/gh/ipfs/go-blockservice.svg?style=svg)](https://circleci.com/gh/ipfs/go-blockservice) 11 | 12 | ## ❗ This repo is no longer maintained. 13 | 👉 We highly recommend switching to the maintained version at https://github.com/ipfs/boxo/tree/main/blockservice. 14 | 🏎️ Good news! There is [tooling and documentation](https://github.com/ipfs/boxo#migrating-to-boxo) to expedite a switch in your repo. 15 | 16 | ⚠️ If you continue using this repo, please note that security fixes will not be provided (unless someone steps in to maintain it). 17 | 18 | 📚 Learn more, including how to take the maintainership mantle or ask questions, [here](https://github.com/ipfs/boxo/wiki/Copied-or-Migrated-Repos-FAQ). 19 | 20 | ## Table of Contents 21 | 22 | - [TODO](#todo) 23 | - [License](#license) 24 | 25 | ## TODO 26 | 27 | The interfaces here really would like to be merged with the blockstore interfaces. 28 | The 'dagservice' constructor currently takes a blockservice, but it would be really nice 29 | if it could just take a blockstore, and have this package implement a blockstore. 30 | 31 | ## License 32 | 33 | MIT © Juan Batiz-Benet 34 | -------------------------------------------------------------------------------- /blockservice.go: -------------------------------------------------------------------------------- 1 | // package blockservice implements a BlockService interface that provides 2 | // a single GetBlock/AddBlock interface that seamlessly retrieves data either 3 | // locally or from a remote peer through the exchange. 4 | package blockservice 5 | 6 | import ( 7 | "context" 8 | "io" 9 | "sync" 10 | 11 | "go.opentelemetry.io/otel/attribute" 12 | "go.opentelemetry.io/otel/trace" 13 | 14 | blocks "github.com/ipfs/go-block-format" 15 | cid "github.com/ipfs/go-cid" 16 | blockstore "github.com/ipfs/go-ipfs-blockstore" 17 | exchange "github.com/ipfs/go-ipfs-exchange-interface" 18 | ipld "github.com/ipfs/go-ipld-format" 19 | logging "github.com/ipfs/go-log/v2" 20 | "github.com/ipfs/go-verifcid" 21 | 22 | "github.com/ipfs/go-blockservice/internal" 23 | ) 24 | 25 | var logger = logging.Logger("blockservice") 26 | 27 | // BlockGetter is the common interface shared between blockservice sessions and 28 | // the blockservice. 29 | // 30 | // Deprecated: use github.com/ipfs/boxo/blockservice.BlockGetter 31 | type BlockGetter interface { 32 | // GetBlock gets the requested block. 33 | GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) 34 | 35 | // GetBlocks does a batch request for the given cids, returning blocks as 36 | // they are found, in no particular order. 37 | // 38 | // It may not be able to find all requested blocks (or the context may 39 | // be canceled). In that case, it will close the channel early. It is up 40 | // to the consumer to detect this situation and keep track which blocks 41 | // it has received and which it hasn't. 42 | GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block 43 | } 44 | 45 | // BlockService is a hybrid block datastore. It stores data in a local 46 | // datastore and may retrieve data from a remote Exchange. 47 | // It uses an internal `datastore.Datastore` instance to store values. 48 | // 49 | // Deprecated: use github.com/ipfs/boxo/blockservice.BlockService 50 | type BlockService interface { 51 | io.Closer 52 | BlockGetter 53 | 54 | // Blockstore returns a reference to the underlying blockstore 55 | Blockstore() blockstore.Blockstore 56 | 57 | // Exchange returns a reference to the underlying exchange (usually bitswap) 58 | Exchange() exchange.Interface 59 | 60 | // AddBlock puts a given block to the underlying datastore 61 | AddBlock(ctx context.Context, o blocks.Block) error 62 | 63 | // AddBlocks adds a slice of blocks at the same time using batching 64 | // capabilities of the underlying datastore whenever possible. 65 | AddBlocks(ctx context.Context, bs []blocks.Block) error 66 | 67 | // DeleteBlock deletes the given block from the blockservice. 68 | DeleteBlock(ctx context.Context, o cid.Cid) error 69 | } 70 | 71 | type blockService struct { 72 | blockstore blockstore.Blockstore 73 | exchange exchange.Interface 74 | // If checkFirst is true then first check that a block doesn't 75 | // already exist to avoid republishing the block on the exchange. 76 | checkFirst bool 77 | } 78 | 79 | // NewBlockService creates a BlockService with given datastore instance. 80 | // 81 | // Deprecated: use github.com/ipfs/boxo/blockservice.New 82 | func New(bs blockstore.Blockstore, rem exchange.Interface) BlockService { 83 | if rem == nil { 84 | logger.Debug("blockservice running in local (offline) mode.") 85 | } 86 | 87 | return &blockService{ 88 | blockstore: bs, 89 | exchange: rem, 90 | checkFirst: true, 91 | } 92 | } 93 | 94 | // NewWriteThrough creates a BlockService that guarantees writes will go 95 | // through to the blockstore and are not skipped by cache checks. 96 | // 97 | // Deprecated: use github.com/ipfs/boxo/blockservice.NewWriteThrough 98 | func NewWriteThrough(bs blockstore.Blockstore, rem exchange.Interface) BlockService { 99 | if rem == nil { 100 | logger.Debug("blockservice running in local (offline) mode.") 101 | } 102 | 103 | return &blockService{ 104 | blockstore: bs, 105 | exchange: rem, 106 | checkFirst: false, 107 | } 108 | } 109 | 110 | // Blockstore returns the blockstore behind this blockservice. 111 | func (s *blockService) Blockstore() blockstore.Blockstore { 112 | return s.blockstore 113 | } 114 | 115 | // Exchange returns the exchange behind this blockservice. 116 | func (s *blockService) Exchange() exchange.Interface { 117 | return s.exchange 118 | } 119 | 120 | // NewSession creates a new session that allows for 121 | // controlled exchange of wantlists to decrease the bandwidth overhead. 122 | // If the current exchange is a SessionExchange, a new exchange 123 | // session will be created. Otherwise, the current exchange will be used 124 | // directly. 125 | // 126 | // Deprecated: use github.com/ipfs/boxo/blockservice.NewSession 127 | func NewSession(ctx context.Context, bs BlockService) *Session { 128 | exch := bs.Exchange() 129 | if sessEx, ok := exch.(exchange.SessionExchange); ok { 130 | return &Session{ 131 | sessCtx: ctx, 132 | ses: nil, 133 | sessEx: sessEx, 134 | bs: bs.Blockstore(), 135 | notifier: exch, 136 | } 137 | } 138 | return &Session{ 139 | ses: exch, 140 | sessCtx: ctx, 141 | bs: bs.Blockstore(), 142 | notifier: exch, 143 | } 144 | } 145 | 146 | // AddBlock adds a particular block to the service, Putting it into the datastore. 147 | func (s *blockService) AddBlock(ctx context.Context, o blocks.Block) error { 148 | ctx, span := internal.StartSpan(ctx, "blockService.AddBlock") 149 | defer span.End() 150 | 151 | c := o.Cid() 152 | // hash security 153 | err := verifcid.ValidateCid(c) 154 | if err != nil { 155 | return err 156 | } 157 | if s.checkFirst { 158 | if has, err := s.blockstore.Has(ctx, c); has || err != nil { 159 | return err 160 | } 161 | } 162 | 163 | if err := s.blockstore.Put(ctx, o); err != nil { 164 | return err 165 | } 166 | 167 | logger.Debugf("BlockService.BlockAdded %s", c) 168 | 169 | if s.exchange != nil { 170 | if err := s.exchange.NotifyNewBlocks(ctx, o); err != nil { 171 | logger.Errorf("NotifyNewBlocks: %s", err.Error()) 172 | } 173 | } 174 | 175 | return nil 176 | } 177 | 178 | func (s *blockService) AddBlocks(ctx context.Context, bs []blocks.Block) error { 179 | ctx, span := internal.StartSpan(ctx, "blockService.AddBlocks") 180 | defer span.End() 181 | 182 | // hash security 183 | for _, b := range bs { 184 | err := verifcid.ValidateCid(b.Cid()) 185 | if err != nil { 186 | return err 187 | } 188 | } 189 | var toput []blocks.Block 190 | if s.checkFirst { 191 | toput = make([]blocks.Block, 0, len(bs)) 192 | for _, b := range bs { 193 | has, err := s.blockstore.Has(ctx, b.Cid()) 194 | if err != nil { 195 | return err 196 | } 197 | if !has { 198 | toput = append(toput, b) 199 | } 200 | } 201 | } else { 202 | toput = bs 203 | } 204 | 205 | if len(toput) == 0 { 206 | return nil 207 | } 208 | 209 | err := s.blockstore.PutMany(ctx, toput) 210 | if err != nil { 211 | return err 212 | } 213 | 214 | if s.exchange != nil { 215 | logger.Debugf("BlockService.BlockAdded %d blocks", len(toput)) 216 | if err := s.exchange.NotifyNewBlocks(ctx, toput...); err != nil { 217 | logger.Errorf("NotifyNewBlocks: %s", err.Error()) 218 | } 219 | } 220 | return nil 221 | } 222 | 223 | // GetBlock retrieves a particular block from the service, 224 | // Getting it from the datastore using the key (hash). 225 | func (s *blockService) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { 226 | ctx, span := internal.StartSpan(ctx, "blockService.GetBlock", trace.WithAttributes(attribute.Stringer("CID", c))) 227 | defer span.End() 228 | 229 | var f func() notifiableFetcher 230 | if s.exchange != nil { 231 | f = s.getExchange 232 | } 233 | 234 | return getBlock(ctx, c, s.blockstore, f) // hash security 235 | } 236 | 237 | func (s *blockService) getExchange() notifiableFetcher { 238 | return s.exchange 239 | } 240 | 241 | func getBlock(ctx context.Context, c cid.Cid, bs blockstore.Blockstore, fget func() notifiableFetcher) (blocks.Block, error) { 242 | err := verifcid.ValidateCid(c) // hash security 243 | if err != nil { 244 | return nil, err 245 | } 246 | 247 | block, err := bs.Get(ctx, c) 248 | if err == nil { 249 | return block, nil 250 | } 251 | 252 | if ipld.IsNotFound(err) && fget != nil { 253 | f := fget() // Don't load the exchange until we have to 254 | 255 | // TODO be careful checking ErrNotFound. If the underlying 256 | // implementation changes, this will break. 257 | logger.Debug("Blockservice: Searching bitswap") 258 | blk, err := f.GetBlock(ctx, c) 259 | if err != nil { 260 | return nil, err 261 | } 262 | // also write in the blockstore for caching, inform the exchange that the block is available 263 | err = bs.Put(ctx, blk) 264 | if err != nil { 265 | return nil, err 266 | } 267 | err = f.NotifyNewBlocks(ctx, blk) 268 | if err != nil { 269 | return nil, err 270 | } 271 | logger.Debugf("BlockService.BlockFetched %s", c) 272 | return blk, nil 273 | } 274 | 275 | logger.Debug("Blockservice GetBlock: Not found") 276 | return nil, err 277 | } 278 | 279 | // GetBlocks gets a list of blocks asynchronously and returns through 280 | // the returned channel. 281 | // NB: No guarantees are made about order. 282 | func (s *blockService) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block { 283 | ctx, span := internal.StartSpan(ctx, "blockService.GetBlocks") 284 | defer span.End() 285 | 286 | var f func() notifiableFetcher 287 | if s.exchange != nil { 288 | f = s.getExchange 289 | } 290 | 291 | return getBlocks(ctx, ks, s.blockstore, f) // hash security 292 | } 293 | 294 | func getBlocks(ctx context.Context, ks []cid.Cid, bs blockstore.Blockstore, fget func() notifiableFetcher) <-chan blocks.Block { 295 | out := make(chan blocks.Block) 296 | 297 | go func() { 298 | defer close(out) 299 | 300 | allValid := true 301 | for _, c := range ks { 302 | if err := verifcid.ValidateCid(c); err != nil { 303 | allValid = false 304 | break 305 | } 306 | } 307 | 308 | if !allValid { 309 | // can't shift in place because we don't want to clobber callers. 310 | ks2 := make([]cid.Cid, 0, len(ks)) 311 | for _, c := range ks { 312 | // hash security 313 | if err := verifcid.ValidateCid(c); err == nil { 314 | ks2 = append(ks2, c) 315 | } else { 316 | logger.Errorf("unsafe CID (%s) passed to blockService.GetBlocks: %s", c, err) 317 | } 318 | } 319 | ks = ks2 320 | } 321 | 322 | var misses []cid.Cid 323 | for _, c := range ks { 324 | hit, err := bs.Get(ctx, c) 325 | if err != nil { 326 | misses = append(misses, c) 327 | continue 328 | } 329 | select { 330 | case out <- hit: 331 | case <-ctx.Done(): 332 | return 333 | } 334 | } 335 | 336 | if len(misses) == 0 || fget == nil { 337 | return 338 | } 339 | 340 | f := fget() // don't load exchange unless we have to 341 | rblocks, err := f.GetBlocks(ctx, misses) 342 | if err != nil { 343 | logger.Debugf("Error with GetBlocks: %s", err) 344 | return 345 | } 346 | 347 | var cache [1]blocks.Block // preallocate once for all iterations 348 | for { 349 | var b blocks.Block 350 | select { 351 | case v, ok := <-rblocks: 352 | if !ok { 353 | return 354 | } 355 | b = v 356 | case <-ctx.Done(): 357 | return 358 | } 359 | 360 | // write in the blockstore for caching 361 | err = bs.Put(ctx, b) 362 | if err != nil { 363 | logger.Errorf("could not write blocks from the network to the blockstore: %s", err) 364 | return 365 | } 366 | 367 | // inform the exchange that the blocks are available 368 | cache[0] = b 369 | err = f.NotifyNewBlocks(ctx, cache[:]...) 370 | if err != nil { 371 | logger.Errorf("could not tell the exchange about new blocks: %s", err) 372 | return 373 | } 374 | cache[0] = nil // early gc 375 | 376 | select { 377 | case out <- b: 378 | case <-ctx.Done(): 379 | return 380 | } 381 | } 382 | }() 383 | return out 384 | } 385 | 386 | // DeleteBlock deletes a block in the blockservice from the datastore 387 | func (s *blockService) DeleteBlock(ctx context.Context, c cid.Cid) error { 388 | ctx, span := internal.StartSpan(ctx, "blockService.DeleteBlock", trace.WithAttributes(attribute.Stringer("CID", c))) 389 | defer span.End() 390 | 391 | err := s.blockstore.DeleteBlock(ctx, c) 392 | if err == nil { 393 | logger.Debugf("BlockService.BlockDeleted %s", c) 394 | } 395 | return err 396 | } 397 | 398 | func (s *blockService) Close() error { 399 | logger.Debug("blockservice is shutting down...") 400 | return s.exchange.Close() 401 | } 402 | 403 | type notifier interface { 404 | NotifyNewBlocks(context.Context, ...blocks.Block) error 405 | } 406 | 407 | // Session is a helper type to provide higher level access to bitswap sessions 408 | // 409 | // Deprecated: use github.com/ipfs/boxo/blockservice.Session 410 | type Session struct { 411 | bs blockstore.Blockstore 412 | ses exchange.Fetcher 413 | sessEx exchange.SessionExchange 414 | sessCtx context.Context 415 | notifier notifier 416 | lk sync.Mutex 417 | } 418 | 419 | type notifiableFetcher interface { 420 | exchange.Fetcher 421 | notifier 422 | } 423 | 424 | type notifiableFetcherWrapper struct { 425 | exchange.Fetcher 426 | notifier 427 | } 428 | 429 | func (s *Session) getSession() notifiableFetcher { 430 | s.lk.Lock() 431 | defer s.lk.Unlock() 432 | if s.ses == nil { 433 | s.ses = s.sessEx.NewSession(s.sessCtx) 434 | } 435 | 436 | return notifiableFetcherWrapper{s.ses, s.notifier} 437 | } 438 | 439 | func (s *Session) getExchange() notifiableFetcher { 440 | return notifiableFetcherWrapper{s.ses, s.notifier} 441 | } 442 | 443 | func (s *Session) getFetcherFactory() func() notifiableFetcher { 444 | if s.sessEx != nil { 445 | return s.getSession 446 | } 447 | if s.ses != nil { 448 | // Our exchange isn't session compatible, let's fallback to non sessions fetches 449 | return s.getExchange 450 | } 451 | return nil 452 | } 453 | 454 | // GetBlock gets a block in the context of a request session 455 | func (s *Session) GetBlock(ctx context.Context, c cid.Cid) (blocks.Block, error) { 456 | ctx, span := internal.StartSpan(ctx, "Session.GetBlock", trace.WithAttributes(attribute.Stringer("CID", c))) 457 | defer span.End() 458 | 459 | return getBlock(ctx, c, s.bs, s.getFetcherFactory()) // hash security 460 | } 461 | 462 | // GetBlocks gets blocks in the context of a request session 463 | func (s *Session) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Block { 464 | ctx, span := internal.StartSpan(ctx, "Session.GetBlocks") 465 | defer span.End() 466 | 467 | return getBlocks(ctx, ks, s.bs, s.getFetcherFactory()) // hash security 468 | } 469 | 470 | var _ BlockGetter = (*Session)(nil) 471 | -------------------------------------------------------------------------------- /blockservice_test.go: -------------------------------------------------------------------------------- 1 | package blockservice 2 | 3 | import ( 4 | "context" 5 | "testing" 6 | 7 | blocks "github.com/ipfs/go-block-format" 8 | cid "github.com/ipfs/go-cid" 9 | ds "github.com/ipfs/go-datastore" 10 | dssync "github.com/ipfs/go-datastore/sync" 11 | blockstore "github.com/ipfs/go-ipfs-blockstore" 12 | butil "github.com/ipfs/go-ipfs-blocksutil" 13 | exchange "github.com/ipfs/go-ipfs-exchange-interface" 14 | offline "github.com/ipfs/go-ipfs-exchange-offline" 15 | ipld "github.com/ipfs/go-ipld-format" 16 | ) 17 | 18 | func TestWriteThroughWorks(t *testing.T) { 19 | bstore := &PutCountingBlockstore{ 20 | blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())), 21 | 0, 22 | } 23 | exchbstore := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) 24 | exch := offline.Exchange(exchbstore) 25 | bserv := NewWriteThrough(bstore, exch) 26 | bgen := butil.NewBlockGenerator() 27 | 28 | block := bgen.Next() 29 | 30 | t.Logf("PutCounter: %d", bstore.PutCounter) 31 | err := bserv.AddBlock(context.Background(), block) 32 | if err != nil { 33 | t.Fatal(err) 34 | } 35 | if bstore.PutCounter != 1 { 36 | t.Fatalf("expected just one Put call, have: %d", bstore.PutCounter) 37 | } 38 | 39 | err = bserv.AddBlock(context.Background(), block) 40 | if err != nil { 41 | t.Fatal(err) 42 | } 43 | if bstore.PutCounter != 2 { 44 | t.Fatalf("Put should have called again, should be 2 is: %d", bstore.PutCounter) 45 | } 46 | } 47 | 48 | func TestExchangeWrite(t *testing.T) { 49 | bstore := &PutCountingBlockstore{ 50 | blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())), 51 | 0, 52 | } 53 | exchbstore := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) 54 | exch := ¬ifyCountingExchange{ 55 | offline.Exchange(exchbstore), 56 | 0, 57 | } 58 | bserv := NewWriteThrough(bstore, exch) 59 | bgen := butil.NewBlockGenerator() 60 | 61 | for name, fetcher := range map[string]BlockGetter{ 62 | "blockservice": bserv, 63 | "session": NewSession(context.Background(), bserv), 64 | } { 65 | t.Run(name, func(t *testing.T) { 66 | // GetBlock 67 | block := bgen.Next() 68 | err := exchbstore.Put(context.Background(), block) 69 | if err != nil { 70 | t.Fatal(err) 71 | } 72 | got, err := fetcher.GetBlock(context.Background(), block.Cid()) 73 | if err != nil { 74 | t.Fatal(err) 75 | } 76 | if got.Cid() != block.Cid() { 77 | t.Fatalf("GetBlock returned unexpected block") 78 | } 79 | if bstore.PutCounter != 1 { 80 | t.Fatalf("expected one Put call, have: %d", bstore.PutCounter) 81 | } 82 | if exch.notifyCount != 1 { 83 | t.Fatalf("expected one NotifyNewBlocks call, have: %d", exch.notifyCount) 84 | } 85 | 86 | // GetBlocks 87 | b1 := bgen.Next() 88 | err = exchbstore.Put(context.Background(), b1) 89 | if err != nil { 90 | t.Fatal(err) 91 | } 92 | b2 := bgen.Next() 93 | err = exchbstore.Put(context.Background(), b2) 94 | if err != nil { 95 | t.Fatal(err) 96 | } 97 | bchan := fetcher.GetBlocks(context.Background(), []cid.Cid{b1.Cid(), b2.Cid()}) 98 | var gotBlocks []blocks.Block 99 | for b := range bchan { 100 | gotBlocks = append(gotBlocks, b) 101 | } 102 | if len(gotBlocks) != 2 { 103 | t.Fatalf("expected to retrieve 2 blocks, got %d", len(gotBlocks)) 104 | } 105 | if bstore.PutCounter != 3 { 106 | t.Fatalf("expected 3 Put call, have: %d", bstore.PutCounter) 107 | } 108 | if exch.notifyCount != 3 { 109 | t.Fatalf("expected one NotifyNewBlocks call, have: %d", exch.notifyCount) 110 | } 111 | 112 | // reset counts 113 | bstore.PutCounter = 0 114 | exch.notifyCount = 0 115 | }) 116 | } 117 | } 118 | 119 | func TestLazySessionInitialization(t *testing.T) { 120 | ctx := context.Background() 121 | ctx, cancel := context.WithCancel(ctx) 122 | defer cancel() 123 | 124 | bstore := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) 125 | bstore2 := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) 126 | bstore3 := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) 127 | session := offline.Exchange(bstore2) 128 | exch := offline.Exchange(bstore3) 129 | sessionExch := &fakeSessionExchange{Interface: exch, session: session} 130 | bservSessEx := NewWriteThrough(bstore, sessionExch) 131 | bgen := butil.NewBlockGenerator() 132 | 133 | block := bgen.Next() 134 | err := bstore.Put(ctx, block) 135 | if err != nil { 136 | t.Fatal(err) 137 | } 138 | block2 := bgen.Next() 139 | err = bstore2.Put(ctx, block2) 140 | if err != nil { 141 | t.Fatal(err) 142 | } 143 | err = session.NotifyNewBlocks(ctx, block2) 144 | if err != nil { 145 | t.Fatal(err) 146 | } 147 | 148 | bsession := NewSession(ctx, bservSessEx) 149 | if bsession.ses != nil { 150 | t.Fatal("Session exchange should not instantiated session immediately") 151 | } 152 | returnedBlock, err := bsession.GetBlock(ctx, block.Cid()) 153 | if err != nil { 154 | t.Fatal("Should have fetched block locally") 155 | } 156 | if returnedBlock.Cid() != block.Cid() { 157 | t.Fatal("Got incorrect block") 158 | } 159 | if bsession.ses != nil { 160 | t.Fatal("Session exchange should not instantiated session if local store had block") 161 | } 162 | returnedBlock, err = bsession.GetBlock(ctx, block2.Cid()) 163 | if err != nil { 164 | t.Fatal("Should have fetched block remotely") 165 | } 166 | if returnedBlock.Cid() != block2.Cid() { 167 | t.Fatal("Got incorrect block") 168 | } 169 | if bsession.ses != session { 170 | t.Fatal("Should have initialized session to fetch block") 171 | } 172 | } 173 | 174 | var _ blockstore.Blockstore = (*PutCountingBlockstore)(nil) 175 | 176 | type PutCountingBlockstore struct { 177 | blockstore.Blockstore 178 | PutCounter int 179 | } 180 | 181 | func (bs *PutCountingBlockstore) Put(ctx context.Context, block blocks.Block) error { 182 | bs.PutCounter++ 183 | return bs.Blockstore.Put(ctx, block) 184 | } 185 | 186 | func (bs *PutCountingBlockstore) PutMany(ctx context.Context, blocks []blocks.Block) error { 187 | bs.PutCounter += len(blocks) 188 | return bs.Blockstore.PutMany(ctx, blocks) 189 | } 190 | 191 | var _ exchange.Interface = (*notifyCountingExchange)(nil) 192 | 193 | type notifyCountingExchange struct { 194 | exchange.Interface 195 | notifyCount int 196 | } 197 | 198 | func (n *notifyCountingExchange) NotifyNewBlocks(ctx context.Context, blocks ...blocks.Block) error { 199 | n.notifyCount += len(blocks) 200 | return n.Interface.NotifyNewBlocks(ctx, blocks...) 201 | } 202 | 203 | var _ exchange.SessionExchange = (*fakeSessionExchange)(nil) 204 | 205 | type fakeSessionExchange struct { 206 | exchange.Interface 207 | session exchange.Fetcher 208 | } 209 | 210 | func (fe *fakeSessionExchange) NewSession(ctx context.Context) exchange.Fetcher { 211 | if ctx == nil { 212 | panic("nil context") 213 | } 214 | return fe.session 215 | } 216 | 217 | func TestNilExchange(t *testing.T) { 218 | ctx := context.Background() 219 | ctx, cancel := context.WithCancel(ctx) 220 | defer cancel() 221 | 222 | bgen := butil.NewBlockGenerator() 223 | block := bgen.Next() 224 | 225 | bs := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) 226 | bserv := NewWriteThrough(bs, nil) 227 | sess := NewSession(ctx, bserv) 228 | _, err := sess.GetBlock(ctx, block.Cid()) 229 | if !ipld.IsNotFound(err) { 230 | t.Fatal("expected block to not be found") 231 | } 232 | err = bs.Put(ctx, block) 233 | if err != nil { 234 | t.Fatal(err) 235 | } 236 | b, err := sess.GetBlock(ctx, block.Cid()) 237 | if err != nil { 238 | t.Fatal(err) 239 | } 240 | if b.Cid() != block.Cid() { 241 | t.Fatal("got the wrong block") 242 | } 243 | } 244 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ipfs/go-blockservice 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/ipfs/go-bitswap v0.11.0 7 | github.com/ipfs/go-block-format v0.0.3 8 | github.com/ipfs/go-cid v0.3.2 9 | github.com/ipfs/go-datastore v0.6.0 10 | github.com/ipfs/go-ipfs-blockstore v1.2.0 11 | github.com/ipfs/go-ipfs-blocksutil v0.0.1 12 | github.com/ipfs/go-ipfs-delay v0.0.1 13 | github.com/ipfs/go-ipfs-exchange-interface v0.2.0 14 | github.com/ipfs/go-ipfs-exchange-offline v0.3.0 15 | github.com/ipfs/go-ipfs-routing v0.3.0 16 | github.com/ipfs/go-ipfs-util v0.0.2 17 | github.com/ipfs/go-ipld-format v0.3.0 18 | github.com/ipfs/go-log/v2 v2.5.1 19 | github.com/ipfs/go-verifcid v0.0.1 20 | go.opentelemetry.io/otel v1.7.0 21 | go.opentelemetry.io/otel/trace v1.7.0 22 | ) 23 | 24 | require ( 25 | github.com/benbjohnson/clock v1.3.0 // indirect 26 | github.com/cskr/pubsub v1.0.2 // indirect 27 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect 28 | github.com/go-logr/logr v1.2.3 // indirect 29 | github.com/go-logr/stdr v1.2.2 // indirect 30 | github.com/gogo/protobuf v1.3.2 // indirect 31 | github.com/google/gopacket v1.1.19 // indirect 32 | github.com/google/uuid v1.3.0 // indirect 33 | github.com/hashicorp/golang-lru v0.5.4 // indirect 34 | github.com/huin/goupnp v1.0.3 // indirect 35 | github.com/ipfs/bbloom v0.0.4 // indirect 36 | github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect 37 | github.com/ipfs/go-ipfs-pq v0.0.2 // indirect 38 | github.com/ipfs/go-log v1.0.5 // indirect 39 | github.com/ipfs/go-metrics-interface v0.0.1 // indirect 40 | github.com/ipfs/go-peertaskqueue v0.8.0 // indirect 41 | github.com/jackpal/go-nat-pmp v1.0.2 // indirect 42 | github.com/jbenet/goprocess v0.1.4 // indirect 43 | github.com/klauspost/cpuid/v2 v2.1.0 // indirect 44 | github.com/koron/go-ssdp v0.0.3 // indirect 45 | github.com/kr/pretty v0.2.1 // indirect 46 | github.com/libp2p/go-buffer-pool v0.1.0 // indirect 47 | github.com/libp2p/go-cidranger v1.1.0 // indirect 48 | github.com/libp2p/go-libp2p v0.22.0 // indirect 49 | github.com/libp2p/go-libp2p-asn-util v0.2.0 // indirect 50 | github.com/libp2p/go-libp2p-record v0.2.0 // indirect 51 | github.com/libp2p/go-libp2p-testing v0.12.0 // indirect 52 | github.com/libp2p/go-msgio v0.2.0 // indirect 53 | github.com/libp2p/go-nat v0.1.0 // indirect 54 | github.com/libp2p/go-netroute v0.2.0 // indirect 55 | github.com/libp2p/go-openssl v0.1.0 // indirect 56 | github.com/mattn/go-isatty v0.0.16 // indirect 57 | github.com/mattn/go-pointer v0.0.1 // indirect 58 | github.com/miekg/dns v1.1.50 // indirect 59 | github.com/minio/sha256-simd v1.0.0 // indirect 60 | github.com/mr-tron/base58 v1.2.0 // indirect 61 | github.com/multiformats/go-base32 v0.0.4 // indirect 62 | github.com/multiformats/go-base36 v0.1.0 // indirect 63 | github.com/multiformats/go-multiaddr v0.7.0 // indirect 64 | github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect 65 | github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect 66 | github.com/multiformats/go-multibase v0.1.1 // indirect 67 | github.com/multiformats/go-multicodec v0.5.0 // indirect 68 | github.com/multiformats/go-multihash v0.2.1 // indirect 69 | github.com/multiformats/go-multistream v0.3.3 // indirect 70 | github.com/multiformats/go-varint v0.0.6 // indirect 71 | github.com/opentracing/opentracing-go v1.2.0 // indirect 72 | github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 // indirect 73 | github.com/spaolacci/murmur3 v1.1.0 // indirect 74 | go.uber.org/atomic v1.10.0 // indirect 75 | go.uber.org/multierr v1.8.0 // indirect 76 | go.uber.org/zap v1.22.0 // indirect 77 | golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect 78 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect 79 | golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect 80 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect 81 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect 82 | golang.org/x/tools v0.1.12 // indirect 83 | lukechampine.com/blake3 v1.1.7 // indirect 84 | ) 85 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 3 | github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= 4 | github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= 5 | github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= 6 | github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= 7 | github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= 8 | github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE= 9 | github.com/containerd/cgroups v1.0.4 h1:jN/mbWBEaz+T1pi5OFtnkQ+8qnmEbAr1Oo1FRm5B0dA= 10 | github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= 11 | github.com/cskr/pubsub v1.0.2 h1:vlOzMhl6PFn60gRlTQQsIfVwaPB/B/8MziK8FhEPt/0= 12 | github.com/cskr/pubsub v1.0.2/go.mod h1:/8MzYXk/NJAz782G8RPkFzXTZVu63VotefPnR9TIRis= 13 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 14 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 15 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 16 | github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= 17 | github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= 18 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4= 19 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= 20 | github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= 21 | github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= 22 | github.com/flynn/noise v1.0.0 h1:DlTHqmzmvcEiKj+4RYo/imoswx/4r6iBlCMfVtrMXpQ= 23 | github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= 24 | github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= 25 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 26 | github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= 27 | github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 28 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 29 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 30 | github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= 31 | github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= 32 | github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= 33 | github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= 34 | github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 35 | github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= 36 | github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= 37 | github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= 38 | github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= 39 | github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM= 40 | github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= 41 | github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= 42 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 43 | github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 44 | github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= 45 | github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 46 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 47 | github.com/gxed/hashland/keccakpg v0.0.1/go.mod h1:kRzw3HkwxFU1mpmPP8v1WyQzwdGfmKFJ6tItnhQ67kU= 48 | github.com/gxed/hashland/murmur3 v0.0.1/go.mod h1:KjXop02n4/ckmZSnY2+HKcLud/tcmvhST0bie/0lS48= 49 | github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= 50 | github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= 51 | github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc= 52 | github.com/huin/goupnp v1.0.3 h1:N8No57ls+MnjlB+JPiCVSOyy/ot7MJTqlo7rn+NYSqQ= 53 | github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y= 54 | github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o= 55 | github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs= 56 | github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0= 57 | github.com/ipfs/go-bitswap v0.11.0 h1:j1WVvhDX1yhG32NTC9xfxnqycqYIlhzEzLXG/cU1HyQ= 58 | github.com/ipfs/go-bitswap v0.11.0/go.mod h1:05aE8H3XOU+LXpTedeAS0OZpcO1WFsj5niYQH9a1Tmk= 59 | github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJgCQF+KIgOPJY= 60 | github.com/ipfs/go-block-format v0.0.3 h1:r8t66QstRp/pd/or4dpnbVfXT5Gt7lOqRvC+/dDTpMc= 61 | github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk= 62 | github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= 63 | github.com/ipfs/go-cid v0.0.2/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= 64 | github.com/ipfs/go-cid v0.0.5/go.mod h1:plgt+Y5MnOey4vO4UlUazGqdbEXuFYitED67FexhXog= 65 | github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= 66 | github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc= 67 | github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw= 68 | github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk= 69 | github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk= 70 | github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8= 71 | github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= 72 | github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= 73 | github.com/ipfs/go-ipfs-blockstore v1.2.0 h1:n3WTeJ4LdICWs/0VSfjHrlqpPpl6MZ+ySd3j8qz0ykw= 74 | github.com/ipfs/go-ipfs-blockstore v1.2.0/go.mod h1:eh8eTFLiINYNSNawfZOC7HOxNTxpB1PFuA5E1m/7exE= 75 | github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= 76 | github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= 77 | github.com/ipfs/go-ipfs-delay v0.0.0-20181109222059-70721b86a9a8/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= 78 | github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= 79 | github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= 80 | github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= 81 | github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= 82 | github.com/ipfs/go-ipfs-exchange-interface v0.2.0 h1:8lMSJmKogZYNo2jjhUs0izT+dck05pqUw4mWNW9Pw6Y= 83 | github.com/ipfs/go-ipfs-exchange-interface v0.2.0/go.mod h1:z6+RhJuDQbqKguVyslSOuVDhqF9JtTrO3eptSAiW2/Y= 84 | github.com/ipfs/go-ipfs-exchange-offline v0.3.0 h1:c/Dg8GDPzixGd0MC8Jh6mjOwU57uYokgWRFidfvEkuA= 85 | github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB02e++Z7521fMxqCNRrz9s= 86 | github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY= 87 | github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY= 88 | github.com/ipfs/go-ipfs-routing v0.3.0 h1:9W/W3N+g+y4ZDeffSgqhgo7BsBSJwPMcyssET9OWevc= 89 | github.com/ipfs/go-ipfs-routing v0.3.0/go.mod h1:dKqtTFIql7e1zYsEuWLyuOU+E0WJWW8JjbTPLParDWo= 90 | github.com/ipfs/go-ipfs-util v0.0.1/go.mod h1:spsl5z8KUnrve+73pOhSVZND1SIxPW5RyBCNzQxlJBc= 91 | github.com/ipfs/go-ipfs-util v0.0.2 h1:59Sswnk1MFaiq+VcaknX7aYEyGyGDAA73ilhEK2POp8= 92 | github.com/ipfs/go-ipfs-util v0.0.2/go.mod h1:CbPtkWJzjLdEcezDns2XYaehFVNXG9zrdrtMecczcsQ= 93 | github.com/ipfs/go-ipld-format v0.3.0 h1:Mwm2oRLzIuUwEPewWAWyMuuBQUsn3awfFEYVb8akMOQ= 94 | github.com/ipfs/go-ipld-format v0.3.0/go.mod h1:co/SdBE8h99968X0hViiw1MNlh6fvxxnHpvVLnH7jSM= 95 | github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM= 96 | github.com/ipfs/go-log v1.0.5 h1:2dOuUCB1Z7uoczMWgAyDck5JLb72zHzrMnGnCNNbvY8= 97 | github.com/ipfs/go-log v1.0.5/go.mod h1:j0b8ZoR+7+R99LD9jZ6+AJsrzkPbSXbZfGakb5JPtIo= 98 | github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Axpmri6g= 99 | github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= 100 | github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= 101 | github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= 102 | github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= 103 | github.com/ipfs/go-peertaskqueue v0.8.0 h1:JyNO144tfu9bx6Hpo119zvbEL9iQ760FHOiJYsUjqaU= 104 | github.com/ipfs/go-peertaskqueue v0.8.0/go.mod h1:cz8hEnnARq4Du5TGqiWKgMr/BOSQ5XOgMOh1K5YYKKM= 105 | github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E= 106 | github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0= 107 | github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= 108 | github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= 109 | github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= 110 | github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= 111 | github.com/jbenet/goprocess v0.1.4 h1:DRGOFReOMqqDNXwW70QkacFW0YN9QnwLV0Vqk+3oU0o= 112 | github.com/jbenet/goprocess v0.1.4/go.mod h1:5yspPrukOVuOLORacaBi858NqyClJPQxYZlqdZVfqY4= 113 | github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= 114 | github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 115 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 116 | github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= 117 | github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 118 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 119 | github.com/klauspost/cpuid/v2 v2.1.0 h1:eyi1Ad2aNJMW95zcSbmGg7Cg6cq3ADwLpMAP96d8rF0= 120 | github.com/klauspost/cpuid/v2 v2.1.0/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= 121 | github.com/koron/go-ssdp v0.0.0-20191105050749-2e1c40ed0b5d/go.mod h1:5Ky9EC2xfoUKUor0Hjgi2BJhCSXJfMOFlmyYrVKGQMk= 122 | github.com/koron/go-ssdp v0.0.3 h1:JivLMY45N76b4p/vsWGOKewBQu6uf39y8l+AQ7sDKx8= 123 | github.com/koron/go-ssdp v0.0.3/go.mod h1:b2MxI6yh02pKrsyNoQUsk4+YNikaGhe4894J+Q5lDvA= 124 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 125 | github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 126 | github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= 127 | github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= 128 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 129 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 130 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 131 | github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= 132 | github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= 133 | github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= 134 | github.com/libp2p/go-cidranger v1.1.0/go.mod h1:KWZTfSr+r9qEo9OkI9/SIEeAtw+NNoU0dXIXt15Okic= 135 | github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= 136 | github.com/libp2p/go-libp2p v0.22.0 h1:2Tce0kHOp5zASFKJbNzRElvh0iZwdtG5uZheNW8chIw= 137 | github.com/libp2p/go-libp2p v0.22.0/go.mod h1:UDolmweypBSjQb2f7xutPnwZ/fxioLbMBxSjRksxxU4= 138 | github.com/libp2p/go-libp2p-asn-util v0.2.0 h1:rg3+Os8jbnO5DxkC7K/Utdi+DkY3q/d1/1q+8WeNAsw= 139 | github.com/libp2p/go-libp2p-asn-util v0.2.0/go.mod h1:WoaWxbHKBymSN41hWSq/lGKJEca7TNm58+gGJi2WsLI= 140 | github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3queqa1NkQ0= 141 | github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk= 142 | github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= 143 | github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= 144 | github.com/libp2p/go-msgio v0.2.0 h1:W6shmB+FeynDrUVl2dgFQvzfBZcXiyqY4VmpQLu9FqU= 145 | github.com/libp2p/go-msgio v0.2.0/go.mod h1:dBVM1gW3Jk9XqHkU4eKdGvVHdLa51hoGfll6jMJMSlY= 146 | github.com/libp2p/go-nat v0.1.0 h1:MfVsH6DLcpa04Xr+p8hmVRG4juse0s3J8HyNWYHffXg= 147 | github.com/libp2p/go-nat v0.1.0/go.mod h1:X7teVkwRHNInVNWQiO/tAiAVRwSr5zoRz4YSTC3uRBM= 148 | github.com/libp2p/go-netroute v0.1.2/go.mod h1:jZLDV+1PE8y5XxBySEBgbuVAXbhtuHSdmLPL2n9MKbk= 149 | github.com/libp2p/go-netroute v0.2.0 h1:0FpsbsvuSnAhXFnCY0VLFbJOzaK0VnP0r1QT/o4nWRE= 150 | github.com/libp2p/go-netroute v0.2.0/go.mod h1:Vio7LTzZ+6hoT4CMZi5/6CpY3Snzh2vgZhWgxMNwlQI= 151 | github.com/libp2p/go-openssl v0.1.0 h1:LBkKEcUv6vtZIQLVTegAil8jbNpJErQ9AnT+bWV+Ooo= 152 | github.com/libp2p/go-openssl v0.1.0/go.mod h1:OiOxwPpL3n4xlenjx2h7AwSGaFSC/KZvf6gNdOBQMtc= 153 | github.com/libp2p/go-reuseport v0.2.0 h1:18PRvIMlpY6ZK85nIAicSBuXXvrYoSw3dsBAR7zc560= 154 | github.com/libp2p/go-sockaddr v0.0.2/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= 155 | github.com/libp2p/go-yamux/v3 v3.1.2 h1:lNEy28MBk1HavUAlzKgShp+F6mn/ea1nDYWftZhFW9Q= 156 | github.com/lucas-clemente/quic-go v0.28.1 h1:Uo0lvVxWg5la9gflIF9lwa39ONq85Xq2D91YNEIslzU= 157 | github.com/marten-seemann/qtls-go1-16 v0.1.5 h1:o9JrYPPco/Nukd/HpOHMHZoBDXQqoNtUCmny98/1uqQ= 158 | github.com/marten-seemann/qtls-go1-17 v0.1.2 h1:JADBlm0LYiVbuSySCHeY863dNkcpMmDR7s0bLKJeYlQ= 159 | github.com/marten-seemann/qtls-go1-18 v0.1.2 h1:JH6jmzbduz0ITVQ7ShevK10Av5+jBEKAHMntXmIV7kM= 160 | github.com/marten-seemann/qtls-go1-19 v0.1.0 h1:rLFKD/9mp/uq1SYGYuVZhm83wkmU95pK5df3GufyYYU= 161 | github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= 162 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 163 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 164 | github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= 165 | github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= 166 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 167 | github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= 168 | github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= 169 | github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= 170 | github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= 171 | github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= 172 | github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= 173 | github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= 174 | github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= 175 | github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= 176 | github.com/minio/sha256-simd v0.0.0-20190131020904-2d45a736cd16/go.mod h1:2FMWW+8GMoPweT6+pI63m9YE3Lmw4J71hV56Chs1E/U= 177 | github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= 178 | github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= 179 | github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= 180 | github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8= 181 | github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 182 | github.com/mr-tron/base58 v1.1.3/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 183 | github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= 184 | github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= 185 | github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA= 186 | github.com/multiformats/go-base32 v0.0.4 h1:+qMh4a2f37b4xTNs6mqitDinryCI+tfO2dRVMN9mjSE= 187 | github.com/multiformats/go-base32 v0.0.4/go.mod h1:jNLFzjPZtp3aIARHbJRZIaPuspdH0J6q39uUM5pnABM= 188 | github.com/multiformats/go-base36 v0.1.0 h1:JR6TyF7JjGd3m6FbLU2cOxhC0Li8z8dLNGQ89tUg4F4= 189 | github.com/multiformats/go-base36 v0.1.0/go.mod h1:kFGE83c6s80PklsHO9sRn2NCoffoRdUUOENyW/Vv6sM= 190 | github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= 191 | github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= 192 | github.com/multiformats/go-multiaddr v0.7.0 h1:gskHcdaCyPtp9XskVwtvEeQOG465sCohbQIirSyqxrc= 193 | github.com/multiformats/go-multiaddr v0.7.0/go.mod h1:Fs50eBDWvZu+l3/9S6xAE7ZYj6yhxlvaVZjakWN7xRs= 194 | github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= 195 | github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= 196 | github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= 197 | github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= 198 | github.com/multiformats/go-multibase v0.0.1/go.mod h1:bja2MqRZ3ggyXtZSEDKpl0uO/gviWFaSteVbWT51qgs= 199 | github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPwIdYQD509ZjSb5y9Oc= 200 | github.com/multiformats/go-multibase v0.1.1 h1:3ASCDsuLX8+j4kx58qnJ4YFq/JWTJpCyDW27ztsVTOI= 201 | github.com/multiformats/go-multibase v0.1.1/go.mod h1:ZEjHE+IsUrgp5mhlEAYjMtZwK1k4haNkcaPg9aoe1a8= 202 | github.com/multiformats/go-multicodec v0.5.0 h1:EgU6cBe/D7WRwQb1KmnBvU7lrcFGMggZVTPtOW9dDHs= 203 | github.com/multiformats/go-multicodec v0.5.0/go.mod h1:DiY2HFaEp5EhEXb/iYzVAunmyX/aSFMxq2KMKfWEues= 204 | github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U= 205 | github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= 206 | github.com/multiformats/go-multihash v0.0.13/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= 207 | github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUjdtcVwxObEQBtRfuyjc= 208 | github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108= 209 | github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc= 210 | github.com/multiformats/go-multistream v0.3.3 h1:d5PZpjwRgVlbwfdTDjife7XszfZd8KYWfROYFlGcR8o= 211 | github.com/multiformats/go-multistream v0.3.3/go.mod h1:ODRoqamLUsETKS9BNcII4gcRsJBU5VAwRIv7O39cEXg= 212 | github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= 213 | github.com/multiformats/go-varint v0.0.5/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= 214 | github.com/multiformats/go-varint v0.0.6 h1:gk85QWKxh3TazbLxED/NlDVv8+q+ReFJk7Y2W/KhfNY= 215 | github.com/multiformats/go-varint v0.0.6/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= 216 | github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= 217 | github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= 218 | github.com/opencontainers/runtime-spec v1.0.2 h1:UfAcuLBJB9Coz72x1hgl8O5RVzTdNiaglX6v2DM6FI0= 219 | github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= 220 | github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= 221 | github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= 222 | github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= 223 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 224 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 225 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 226 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 227 | github.com/prometheus/client_golang v1.12.1 h1:ZiaPsmm9uiBeaSMRznKsCDNtPCS0T3JVDGF+06gjBzk= 228 | github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M= 229 | github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= 230 | github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= 231 | github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= 232 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 233 | github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572 h1:RC6RW7j+1+HkWaX/Yh71Ee5ZHaHYt7ZP4sQgUrm6cDU= 234 | github.com/spacemonkeygo/spacelog v0.0.0-20180420211403-2296661a0572/go.mod h1:w0SWMsp6j9O/dk4/ZpIhL+3CkG8ofA2vuv7k+ltqUMc= 235 | github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= 236 | github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= 237 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 238 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 239 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 240 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 241 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 242 | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= 243 | github.com/whyrusleeping/go-logging v0.0.0-20170515211332-0457bb6b88fc/go.mod h1:bopw91TMyo8J3tvftk8xmU2kPmlrt4nScJQZU2hE5EM= 244 | github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 245 | github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= 246 | github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 247 | go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM= 248 | go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk= 249 | go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o= 250 | go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU= 251 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 252 | go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= 253 | go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= 254 | go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= 255 | go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= 256 | go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA= 257 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 258 | go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= 259 | go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= 260 | go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= 261 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 262 | go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= 263 | go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= 264 | go.uber.org/zap v1.22.0 h1:Zcye5DUgBloQ9BaT4qc9BnjOFog5TvBSAGkJ3Nf70c0= 265 | go.uber.org/zap v1.22.0/go.mod h1:H4siCOZOrAolnUPJEkfaSjDqyP+BDS0DdDWzwcgt3+U= 266 | golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= 267 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 268 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 269 | golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 270 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 271 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 272 | golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= 273 | golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 274 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 275 | golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= 276 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 277 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 278 | golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 279 | golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 280 | golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= 281 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= 282 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 283 | golang.org/x/net v0.0.0-20181011144130-49bb7cea24b1/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 284 | golang.org/x/net v0.0.0-20190227160552-c95aed5357e7/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 285 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 286 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 287 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 288 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 289 | golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 290 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 291 | golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= 292 | golang.org/x/net v0.0.0-20210423184538-5f58ad60dda6/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= 293 | golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 294 | golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E= 295 | golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= 296 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 297 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 298 | golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 299 | golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 300 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw= 301 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 302 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 303 | golang.org/x/sys v0.0.0-20190219092855-153ac476189d/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 304 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 305 | golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 306 | golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 307 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 308 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 309 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 310 | golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 311 | golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 312 | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 313 | golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 314 | golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 315 | golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 316 | golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 317 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= 318 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 319 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 320 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 321 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 322 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 323 | golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 324 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 325 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 326 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 327 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 328 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 329 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 330 | golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 331 | golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= 332 | golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= 333 | golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 334 | golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= 335 | golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= 336 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 337 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 338 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 339 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 340 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 341 | google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= 342 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 343 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 344 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 345 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 346 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 347 | gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= 348 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 349 | gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 350 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 351 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 352 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 353 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 354 | lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= 355 | lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= 356 | -------------------------------------------------------------------------------- /internal/tracing.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | import ( 4 | "context" 5 | "fmt" 6 | 7 | "go.opentelemetry.io/otel" 8 | "go.opentelemetry.io/otel/trace" 9 | ) 10 | 11 | // Deprecated: use github.com/ipfs/boxo/blockservice/internal.StartSpan 12 | func StartSpan(ctx context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) { 13 | return otel.Tracer("go-blockservice").Start(ctx, fmt.Sprintf("Blockservice.%s", name), opts...) 14 | } 15 | -------------------------------------------------------------------------------- /test/blocks_test.go: -------------------------------------------------------------------------------- 1 | package bstest 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "fmt" 7 | "testing" 8 | "time" 9 | 10 | . "github.com/ipfs/go-blockservice" 11 | 12 | blocks "github.com/ipfs/go-block-format" 13 | cid "github.com/ipfs/go-cid" 14 | ds "github.com/ipfs/go-datastore" 15 | dssync "github.com/ipfs/go-datastore/sync" 16 | blockstore "github.com/ipfs/go-ipfs-blockstore" 17 | offline "github.com/ipfs/go-ipfs-exchange-offline" 18 | u "github.com/ipfs/go-ipfs-util" 19 | ) 20 | 21 | func newObject(data []byte) blocks.Block { 22 | return blocks.NewBlock(data) 23 | } 24 | 25 | func TestBlocks(t *testing.T) { 26 | bstore := blockstore.NewBlockstore(dssync.MutexWrap(ds.NewMapDatastore())) 27 | bs := New(bstore, offline.Exchange(bstore)) 28 | defer bs.Close() 29 | 30 | o := newObject([]byte("beep boop")) 31 | h := cid.NewCidV0(u.Hash([]byte("beep boop"))) 32 | if !o.Cid().Equals(h) { 33 | t.Error("Block key and data multihash key not equal") 34 | } 35 | 36 | err := bs.AddBlock(context.Background(), o) 37 | if err != nil { 38 | t.Error("failed to add block to BlockService", err) 39 | return 40 | } 41 | 42 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) 43 | defer cancel() 44 | b2, err := bs.GetBlock(ctx, o.Cid()) 45 | if err != nil { 46 | t.Error("failed to retrieve block from BlockService", err) 47 | return 48 | } 49 | 50 | if !o.Cid().Equals(b2.Cid()) { 51 | t.Error("Block keys not equal.") 52 | } 53 | 54 | if !bytes.Equal(o.RawData(), b2.RawData()) { 55 | t.Error("Block data is not equal.") 56 | } 57 | } 58 | 59 | func makeObjects(n int) []blocks.Block { 60 | var out []blocks.Block 61 | for i := 0; i < n; i++ { 62 | out = append(out, newObject([]byte(fmt.Sprintf("object %d", i)))) 63 | } 64 | return out 65 | } 66 | 67 | func TestGetBlocksSequential(t *testing.T) { 68 | var servs = Mocks(4) 69 | for _, s := range servs { 70 | defer s.Close() 71 | } 72 | objs := makeObjects(50) 73 | 74 | var cids []cid.Cid 75 | for _, o := range objs { 76 | cids = append(cids, o.Cid()) 77 | err := servs[0].AddBlock(context.Background(), o) 78 | if err != nil { 79 | t.Fatal(err) 80 | } 81 | } 82 | 83 | t.Log("one instance at a time, get blocks concurrently") 84 | 85 | for i := 1; i < len(servs); i++ { 86 | ctx, cancel := context.WithTimeout(context.Background(), time.Second*50) 87 | defer cancel() 88 | out := servs[i].GetBlocks(ctx, cids) 89 | gotten := make(map[string]blocks.Block) 90 | for blk := range out { 91 | if _, ok := gotten[blk.Cid().KeyString()]; ok { 92 | t.Fatal("Got duplicate block!") 93 | } 94 | gotten[blk.Cid().KeyString()] = blk 95 | } 96 | if len(gotten) != len(objs) { 97 | t.Fatalf("Didnt get enough blocks back: %d/%d", len(gotten), len(objs)) 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /test/mock.go: -------------------------------------------------------------------------------- 1 | package bstest 2 | 3 | import ( 4 | testinstance "github.com/ipfs/go-bitswap/testinstance" 5 | tn "github.com/ipfs/go-bitswap/testnet" 6 | "github.com/ipfs/go-blockservice" 7 | delay "github.com/ipfs/go-ipfs-delay" 8 | mockrouting "github.com/ipfs/go-ipfs-routing/mock" 9 | ) 10 | 11 | // Mocks returns |n| connected mock Blockservices 12 | // 13 | // Deprecated: use github.com/ipfs/boxo/blockservice/test.Mocks 14 | func Mocks(n int) []blockservice.BlockService { 15 | net := tn.VirtualNetwork(mockrouting.NewServer(), delay.Fixed(0)) 16 | sg := testinstance.NewTestInstanceGenerator(net, nil, nil) 17 | 18 | instances := sg.Instances(n) 19 | 20 | var servs []blockservice.BlockService 21 | for _, i := range instances { 22 | servs = append(servs, blockservice.New(i.Blockstore(), i.Exchange)) 23 | } 24 | return servs 25 | } 26 | -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "v0.5.2" 3 | } 4 | --------------------------------------------------------------------------------