From 89248079aaf6689e010d5ea1dd689ed717f0c8b6 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 20 Feb 2024 09:51:16 +0100 Subject: [PATCH 01/12] docs: use tag link instead of branch (#583) --- RELEASE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE.md b/RELEASE.md index 3d6ac8400..cecd4dad5 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -85,7 +85,7 @@ Below are links of related/adjacent work that has informed some of the decisions - [ ] Merge the PR into `release`, _using "Create a Merge Commit"_, and do not delete the `release-vX.Y.X` branch - [ ] Verify the tag is created - [ ] Announce the release - - [ ] Click [this link](https://discuss.ipfs.tech/new-topic?title=Boxo%20vX.Y.Z%20is%20out%21&tags=boxo&category=News&body=%23%23%20Boxo%20vX.Y.Z%20is%20out%21%0A%0ASee%3A%0A-%20Code%3A%20https%3A%2F%2Fgithub.com%2Fipfs%2Fboxo%2Freleases%2Ftag%2FvX.Y.Z%0A-%20Release%20Notes%3A%20https%3A%2F%2Fgithub.com%2Fipfs%2Fboxo%2Fblob%2Frelease-vX.Y.Z%2FCHANGELOG.md) to start a new Discourse topic + - [ ] Click [this link](https://discuss.ipfs.tech/new-topic?title=Boxo%20vX.Y.Z%20is%20out%21&tags=boxo&category=News&body=%23%23%20Boxo%20vX.Y.Z%20is%20out%21%0A%0ASee%3A%0A-%20Code%3A%20https%3A%2F%2Fgithub.com%2Fipfs%2Fboxo%2Freleases%2Ftag%2FvX.Y.Z%0A-%20Release%20Notes%3A%20https%3A%2F%2Fgithub.com%2Fipfs%2Fboxo%2Fblob%2FvX.Y.Z%2FCHANGELOG.md) to start a new Discourse topic - [ ] Update `vX.Y.Z` in the title and body - [ ] Create the topic - [ ] Create a PR merging `release` into `main` From 97e347e5e18be3b6cb30f441277142c71adea770 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Tue, 5 Mar 2024 18:19:55 +0100 Subject: [PATCH 02/12] fix(routing/http): support legacy peerids we already return base58, but we did not support them as input. libp2p specs state implementations MUST support both, it is also better for end users if we are liberal in inputs and support both notations: https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation --- CHANGELOG.md | 2 + routing/http/server/server.go | 17 ++++--- routing/http/server/server_test.go | 82 +++++++++++++++++++++++++++--- 3 files changed, 87 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 785b27904..3d148b03c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ The following emojis are used to highlight certain changes: ### Fixed +- 🛠️`routing/http/server`: delegated peer routing endpoint now supports both [PeerID string notaitons from libp2p specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation). + ### Security ## [v0.18.0] diff --git a/routing/http/server/server.go b/routing/http/server/server.go index d9be47eb2..df93c57fd 100644 --- a/routing/http/server/server.go +++ b/routing/http/server/server.go @@ -242,16 +242,21 @@ func (s *server) findProvidersNDJSON(w http.ResponseWriter, provIter iter.Result func (s *server) findPeers(w http.ResponseWriter, r *http.Request) { pidStr := mux.Vars(r)["peer-id"] - // pidStr must be in CIDv1 format. Therefore, use [cid.Decode]. We can't use - // [peer.Decode] because that would allow other formats to pass through. + // While specification states that peer-id is expected to be in CIDv1 format, reality + // is the clients will often learn legacy PeerID string from other sources, + // and try to use it. + // See https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation + // We are liberal in inputs here, and uplift legacy PeerID to CID if necessary. + // Rationale: it is better to fix this common mistake than to error and break peer routing. cid, err := cid.Decode(pidStr) if err != nil { - if pid, err := peer.Decode(pidStr); err == nil { - writeErr(w, "FindPeers", http.StatusBadRequest, fmt.Errorf("the value is a peer ID, try using its CID representation: %s", peer.ToCid(pid).String())) + // check if input is peer ID in legacy format + if pid, err2 := peer.Decode(pidStr); err2 == nil { + cid = peer.ToCid(pid) } else { - writeErr(w, "FindPeers", http.StatusBadRequest, fmt.Errorf("unable to parse peer ID: %w", err)) + writeErr(w, "FindPeers", http.StatusBadRequest, fmt.Errorf("unable to parse peer ID as libp2p-key CID: %w", err)) + return } - return } pid, err := peer.FromCid(cid) diff --git a/routing/http/server/server_test.go b/routing/http/server/server_test.go index f823ac25a..c767d8f2e 100644 --- a/routing/http/server/server_test.go +++ b/routing/http/server/server_test.go @@ -147,7 +147,7 @@ func TestPeers(t *testing.T) { return resp } - t.Run("GET /routing/v1/peers/{non-peer-cid} returns 400", func(t *testing.T) { + t.Run("GET /routing/v1/peers/{non-peer-valid-cid} returns 400", func(t *testing.T) { t.Parallel() router := &mockContentRouter{} @@ -155,16 +155,79 @@ func TestPeers(t *testing.T) { require.Equal(t, 400, resp.StatusCode) }) - t.Run("GET /routing/v1/peers/{base58-peer-id} returns 400", func(t *testing.T) { + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body (JSON)", func(t *testing.T) { t.Parallel() _, pid := makePeerID(t) + results := iter.FromSlice([]iter.Result[*types.PeerRecord]{ + {Val: &types.PeerRecord{ + Schema: types.SchemaPeer, + ID: &pid, + Protocols: []string{"transport-bitswap", "transport-foo"}, + Addrs: []types.Multiaddr{}, + }}, + {Val: &types.PeerRecord{ + Schema: types.SchemaPeer, + ID: &pid, + Protocols: []string{"transport-foo"}, + Addrs: []types.Multiaddr{}, + }}, + }) + router := &mockContentRouter{} - resp := makeRequest(t, router, mediaTypeJSON, b58.Encode([]byte(pid))) - require.Equal(t, 400, resp.StatusCode) + router.On("FindPeers", mock.Anything, pid, 20).Return(results, nil) + + libp2pKeyCID := peer.ToCid(pid).String() + resp := makeRequest(t, router, mediaTypeJSON, libp2pKeyCID) + require.Equal(t, 200, resp.StatusCode) + + header := resp.Header.Get("Content-Type") + require.Equal(t, mediaTypeJSON, header) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + expectedBody := `{"Peers":[{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-bitswap","transport-foo"],"Schema":"peer"},{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-foo"],"Schema":"peer"}]}` + require.Equal(t, expectedBody, string(body)) + }) + + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body (NDJSON)", func(t *testing.T) { + t.Parallel() + + _, pid := makePeerID(t) + results := iter.FromSlice([]iter.Result[*types.PeerRecord]{ + {Val: &types.PeerRecord{ + Schema: types.SchemaPeer, + ID: &pid, + Protocols: []string{"transport-bitswap", "transport-foo"}, + Addrs: []types.Multiaddr{}, + }}, + {Val: &types.PeerRecord{ + Schema: types.SchemaPeer, + ID: &pid, + Protocols: []string{"transport-foo"}, + Addrs: []types.Multiaddr{}, + }}, + }) + + router := &mockContentRouter{} + router.On("FindPeers", mock.Anything, pid, 0).Return(results, nil) + + libp2pKeyCID := peer.ToCid(pid).String() + resp := makeRequest(t, router, mediaTypeNDJSON, libp2pKeyCID) + require.Equal(t, 200, resp.StatusCode) + + header := resp.Header.Get("Content-Type") + require.Equal(t, mediaTypeNDJSON, header) + + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + + expectedBody := `{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-bitswap","transport-foo"],"Schema":"peer"}` + "\n" + `{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-foo"],"Schema":"peer"}` + "\n" + require.Equal(t, expectedBody, string(body)) }) - t.Run("GET /routing/v1/peers/{cid-peer-id} returns 200 with correct body (JSON)", func(t *testing.T) { + t.Run("GET /routing/v1/peers/{legacy-base58-peer-id} returns 200 with correct body (JSON)", func(t *testing.T) { t.Parallel() _, pid := makePeerID(t) @@ -186,7 +249,8 @@ func TestPeers(t *testing.T) { router := &mockContentRouter{} router.On("FindPeers", mock.Anything, pid, 20).Return(results, nil) - resp := makeRequest(t, router, mediaTypeJSON, peer.ToCid(pid).String()) + legacyPeerID := b58.Encode([]byte(pid)) + resp := makeRequest(t, router, mediaTypeJSON, legacyPeerID) require.Equal(t, 200, resp.StatusCode) header := resp.Header.Get("Content-Type") @@ -199,7 +263,7 @@ func TestPeers(t *testing.T) { require.Equal(t, expectedBody, string(body)) }) - t.Run("GET /routing/v1/peers/{cid-peer-id} returns 200 with correct body (NDJSON)", func(t *testing.T) { + t.Run("GET /routing/v1/peers/{legacy-base58-peer-id} returns 200 with correct body (NDJSON)", func(t *testing.T) { t.Parallel() _, pid := makePeerID(t) @@ -221,7 +285,8 @@ func TestPeers(t *testing.T) { router := &mockContentRouter{} router.On("FindPeers", mock.Anything, pid, 0).Return(results, nil) - resp := makeRequest(t, router, mediaTypeNDJSON, peer.ToCid(pid).String()) + legacyPeerID := b58.Encode([]byte(pid)) + resp := makeRequest(t, router, mediaTypeNDJSON, legacyPeerID) require.Equal(t, 200, resp.StatusCode) header := resp.Header.Get("Content-Type") @@ -233,6 +298,7 @@ func TestPeers(t *testing.T) { expectedBody := `{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-bitswap","transport-foo"],"Schema":"peer"}` + "\n" + `{"Addrs":[],"ID":"` + pid.String() + `","Protocols":["transport-foo"],"Schema":"peer"}` + "\n" require.Equal(t, expectedBody, string(body)) }) + } func makeName(t *testing.T) (crypto.PrivKey, ipns.Name) { From b6b7771fbca0c5079f42b3441f948b5dd547f1e9 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Thu, 7 Mar 2024 09:34:55 +0100 Subject: [PATCH 03/12] routing/http/server: add cache control (#584) --- CHANGELOG.md | 2 + routing/http/server/server.go | 60 ++++++++-- routing/http/server/server_test.go | 164 ++++++++++++++++++++++----- routing/http/types/json/responses.go | 12 ++ 4 files changed, 200 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d148b03c..ecf1ffe2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ The following emojis are used to highlight certain changes: ### Added +* `routing/http/server` now adds `Cache-Control` HTTP header to GET requests: 15 seconds for empty responses, or 5 minutes for responses with providers. + ### Changed ### Removed diff --git a/routing/http/server/server.go b/routing/http/server/server.go index df93c57fd..b00f22012 100644 --- a/routing/http/server/server.go +++ b/routing/http/server/server.go @@ -9,7 +9,6 @@ import ( "io" "mime" "net/http" - "strconv" "strings" "time" @@ -402,15 +401,26 @@ func (s *server) GetIPNS(w http.ResponseWriter, r *http.Request) { return } + var remainingValidity int + // Include 'Expires' header with time when signature expiration happens + if validityType, err := record.ValidityType(); err == nil && validityType == ipns.ValidityEOL { + if validity, err := record.Validity(); err == nil { + w.Header().Set("Expires", validity.UTC().Format(http.TimeFormat)) + remainingValidity = int(time.Until(validity).Seconds()) + } + } else { + remainingValidity = int(ipns.DefaultRecordLifetime.Seconds()) + } if ttl, err := record.TTL(); err == nil { - w.Header().Set("Cache-Control", fmt.Sprintf("max-age=%d", int(ttl.Seconds()))) + setCacheControl(w, int(ttl.Seconds()), remainingValidity) } else { - w.Header().Set("Cache-Control", "max-age=60") + setCacheControl(w, int(ipns.DefaultRecordTTL.Seconds()), remainingValidity) } + w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) - recordEtag := strconv.FormatUint(xxhash.Sum64(rawRecord), 32) - w.Header().Set("Etag", recordEtag) + w.Header().Set("Etag", fmt.Sprintf(`"%x"`, xxhash.Sum64(rawRecord))) w.Header().Set("Content-Type", mediaTypeIPNSRecord) + w.Header().Add("Vary", "Accept") w.Write(rawRecord) } @@ -462,8 +472,30 @@ func (s *server) PutIPNS(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -func writeJSONResult(w http.ResponseWriter, method string, val any) { +var ( + // Rule-of-thumb Cache-Control policy is to work well with caching proxies and load balancers. + // If there are any results, cache on the client for longer, and hint any in-between caches to + // serve cached result and upddate cache in background as long we have + // result that is within Amino DHT expiration window + maxAgeWithResults = int((5 * time.Minute).Seconds()) // cache >0 results for longer + maxAgeWithoutResults = int((15 * time.Second).Seconds()) // cache no results briefly + maxStale = int((48 * time.Hour).Seconds()) // allow stale results as long within Amino DHT Expiration window +) + +func setCacheControl(w http.ResponseWriter, maxAge int, stale int) { + w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d, stale-while-revalidate=%d, stale-if-error=%d", maxAge, stale, stale)) +} + +func writeJSONResult(w http.ResponseWriter, method string, val interface{ Length() int }) { w.Header().Add("Content-Type", mediaTypeJSON) + w.Header().Add("Vary", "Accept") + + if val.Length() > 0 { + setCacheControl(w, maxAgeWithResults, maxStale) + } else { + setCacheControl(w, maxAgeWithoutResults, maxStale) + } + w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) // keep the marshaling separate from the writing, so we can distinguish bugs (which surface as 500) // from transient network issues (which surface as transport errors) @@ -500,14 +532,17 @@ func writeResultsIterNDJSON[T any](w http.ResponseWriter, resultIter iter.Result defer resultIter.Close() w.Header().Set("Content-Type", mediaTypeNDJSON) - w.WriteHeader(http.StatusOK) + w.Header().Add("Vary", "Accept") + w.Header().Set("Last-Modified", time.Now().UTC().Format(http.TimeFormat)) + hasResults := false for resultIter.Next() { res := resultIter.Val() if res.Err != nil { logger.Errorw("ndjson iterator error", "Error", res.Err) return } + // don't use an encoder because we can't easily differentiate writer errors from encoding errors b, err := drjson.MarshalJSONBytes(res.Val) if err != nil { @@ -515,6 +550,12 @@ func writeResultsIterNDJSON[T any](w http.ResponseWriter, resultIter iter.Result return } + if !hasResults { + hasResults = true + // There's results, cache useful result for longer + setCacheControl(w, maxAgeWithResults, maxStale) + } + _, err = w.Write(b) if err != nil { logger.Warn("ndjson write error", "Error", err) @@ -531,4 +572,9 @@ func writeResultsIterNDJSON[T any](w http.ResponseWriter, resultIter iter.Result f.Flush() } } + + if !hasResults { + // There weren't results, cache for shorter + setCacheControl(w, maxAgeWithoutResults, maxStale) + } } diff --git a/routing/http/server/server_test.go b/routing/http/server/server_test.go index c767d8f2e..ea827000f 100644 --- a/routing/http/server/server_test.go +++ b/routing/http/server/server_test.go @@ -7,6 +7,8 @@ import ( "io" "net/http" "net/http/httptest" + "regexp" + "strconv" "testing" "time" @@ -47,6 +49,7 @@ func TestHeaders(t *testing.T) { require.Equal(t, 200, resp.StatusCode) header := resp.Header.Get("Content-Type") require.Equal(t, mediaTypeJSON, header) + require.Equal(t, "Accept", resp.Header.Get("Vary")) resp, err = http.Get(serverAddr + "/routing/v1/providers/" + "BAD_CID") require.NoError(t, err) @@ -66,6 +69,13 @@ func makePeerID(t *testing.T) (crypto.PrivKey, peer.ID) { return sk, pid } +func requireCloseToNow(t *testing.T, lastModified string) { + // inspecting fields like 'Last-Modified' is prone to one-off errors, we test with 1m buffer + lastModifiedTime, err := time.Parse(http.TimeFormat, lastModified) + require.NoError(t, err) + require.WithinDuration(t, time.Now(), lastModifiedTime, 1*time.Minute) +} + func TestProviders(t *testing.T) { pidStr := "12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn" pid2Str := "12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vz" @@ -79,25 +89,31 @@ func TestProviders(t *testing.T) { cid, err := cid.Decode(cidStr) require.NoError(t, err) - runTest := func(t *testing.T, contentType string, expectedStream bool, expectedBody string) { + runTest := func(t *testing.T, contentType string, empty bool, expectedStream bool, expectedBody string) { t.Parallel() - results := iter.FromSlice([]iter.Result[types.Record]{ - {Val: &types.PeerRecord{ - Schema: types.SchemaPeer, - ID: &pid, - Protocols: []string{"transport-bitswap"}, - Addrs: []types.Multiaddr{}, - }}, - //lint:ignore SA1019 // ignore staticcheck - {Val: &types.BitswapRecord{ + var results *iter.SliceIter[iter.Result[types.Record]] + + if empty { + results = iter.FromSlice([]iter.Result[types.Record]{}) + } else { + results = iter.FromSlice([]iter.Result[types.Record]{ + {Val: &types.PeerRecord{ + Schema: types.SchemaPeer, + ID: &pid, + Protocols: []string{"transport-bitswap"}, + Addrs: []types.Multiaddr{}, + }}, //lint:ignore SA1019 // ignore staticcheck - Schema: types.SchemaBitswap, - ID: &pid2, - Protocol: "transport-bitswap", - Addrs: []types.Multiaddr{}, - }}}, - ) + {Val: &types.BitswapRecord{ + //lint:ignore SA1019 // ignore staticcheck + Schema: types.SchemaBitswap, + ID: &pid2, + Protocol: "transport-bitswap", + Addrs: []types.Multiaddr{}, + }}}, + ) + } router := &mockContentRouter{} server := httptest.NewServer(Handler(router)) @@ -117,8 +133,16 @@ func TestProviders(t *testing.T) { resp, err := http.DefaultClient.Do(req) require.NoError(t, err) require.Equal(t, 200, resp.StatusCode) - header := resp.Header.Get("Content-Type") - require.Equal(t, contentType, header) + + require.Equal(t, contentType, resp.Header.Get("Content-Type")) + require.Equal(t, "Accept", resp.Header.Get("Vary")) + + if empty { + require.Equal(t, "public, max-age=15, stale-while-revalidate=172800, stale-if-error=172800", resp.Header.Get("Cache-Control")) + } else { + require.Equal(t, "public, max-age=300, stale-while-revalidate=172800, stale-if-error=172800", resp.Header.Get("Cache-Control")) + } + requireCloseToNow(t, resp.Header.Get("Last-Modified")) body, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -127,11 +151,19 @@ func TestProviders(t *testing.T) { } t.Run("JSON Response", func(t *testing.T) { - runTest(t, mediaTypeJSON, false, `{"Providers":[{"Addrs":[],"ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn","Protocols":["transport-bitswap"],"Schema":"peer"},{"Schema":"bitswap","Protocol":"transport-bitswap","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vz"}]}`) + runTest(t, mediaTypeJSON, false, false, `{"Providers":[{"Addrs":[],"ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn","Protocols":["transport-bitswap"],"Schema":"peer"},{"Schema":"bitswap","Protocol":"transport-bitswap","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vz"}]}`) + }) + + t.Run("Empty JSON Response", func(t *testing.T) { + runTest(t, mediaTypeJSON, true, false, `{"Providers":null}`) }) t.Run("NDJSON Response", func(t *testing.T) { - runTest(t, mediaTypeNDJSON, true, `{"Addrs":[],"ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn","Protocols":["transport-bitswap"],"Schema":"peer"}`+"\n"+`{"Schema":"bitswap","Protocol":"transport-bitswap","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vz"}`+"\n") + runTest(t, mediaTypeNDJSON, false, true, `{"Addrs":[],"ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn","Protocols":["transport-bitswap"],"Schema":"peer"}`+"\n"+`{"Schema":"bitswap","Protocol":"transport-bitswap","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vz"}`+"\n") + }) + + t.Run("Empty NDJSON Response", func(t *testing.T) { + runTest(t, mediaTypeNDJSON, true, true, "") }) } @@ -155,7 +187,26 @@ func TestPeers(t *testing.T) { require.Equal(t, 400, resp.StatusCode) }) - t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body (JSON)", func(t *testing.T) { + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body and headers (No Results, JSON)", func(t *testing.T) { + t.Parallel() + + _, pid := makePeerID(t) + results := iter.FromSlice([]iter.Result[*types.PeerRecord]{}) + + router := &mockContentRouter{} + router.On("FindPeers", mock.Anything, pid, 20).Return(results, nil) + + resp := makeRequest(t, router, mediaTypeJSON, peer.ToCid(pid).String()) + require.Equal(t, 200, resp.StatusCode) + + require.Equal(t, mediaTypeJSON, resp.Header.Get("Content-Type")) + require.Equal(t, "Accept", resp.Header.Get("Vary")) + require.Equal(t, "public, max-age=15, stale-while-revalidate=172800, stale-if-error=172800", resp.Header.Get("Cache-Control")) + + requireCloseToNow(t, resp.Header.Get("Last-Modified")) + }) + + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body and headers (JSON)", func(t *testing.T) { t.Parallel() _, pid := makePeerID(t) @@ -181,8 +232,11 @@ func TestPeers(t *testing.T) { resp := makeRequest(t, router, mediaTypeJSON, libp2pKeyCID) require.Equal(t, 200, resp.StatusCode) - header := resp.Header.Get("Content-Type") - require.Equal(t, mediaTypeJSON, header) + require.Equal(t, mediaTypeJSON, resp.Header.Get("Content-Type")) + require.Equal(t, "Accept", resp.Header.Get("Vary")) + require.Equal(t, "public, max-age=300, stale-while-revalidate=172800, stale-if-error=172800", resp.Header.Get("Cache-Control")) + + requireCloseToNow(t, resp.Header.Get("Last-Modified")) body, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -191,7 +245,26 @@ func TestPeers(t *testing.T) { require.Equal(t, expectedBody, string(body)) }) - t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body (NDJSON)", func(t *testing.T) { + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body and headers (No Results, NDJSON)", func(t *testing.T) { + t.Parallel() + + _, pid := makePeerID(t) + results := iter.FromSlice([]iter.Result[*types.PeerRecord]{}) + + router := &mockContentRouter{} + router.On("FindPeers", mock.Anything, pid, 0).Return(results, nil) + + resp := makeRequest(t, router, mediaTypeNDJSON, peer.ToCid(pid).String()) + require.Equal(t, 200, resp.StatusCode) + + require.Equal(t, mediaTypeNDJSON, resp.Header.Get("Content-Type")) + require.Equal(t, "Accept", resp.Header.Get("Vary")) + require.Equal(t, "public, max-age=15, stale-while-revalidate=172800, stale-if-error=172800", resp.Header.Get("Cache-Control")) + + requireCloseToNow(t, resp.Header.Get("Last-Modified")) + }) + + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body and headers (NDJSON)", func(t *testing.T) { t.Parallel() _, pid := makePeerID(t) @@ -217,8 +290,9 @@ func TestPeers(t *testing.T) { resp := makeRequest(t, router, mediaTypeNDJSON, libp2pKeyCID) require.Equal(t, 200, resp.StatusCode) - header := resp.Header.Get("Content-Type") - require.Equal(t, mediaTypeNDJSON, header) + require.Equal(t, mediaTypeNDJSON, resp.Header.Get("Content-Type")) + require.Equal(t, "Accept", resp.Header.Get("Vary")) + require.Equal(t, "public, max-age=300, stale-while-revalidate=172800, stale-if-error=172800", resp.Header.Get("Cache-Control")) body, err := io.ReadAll(resp.Body) require.NoError(t, err) @@ -254,6 +328,7 @@ func TestPeers(t *testing.T) { require.Equal(t, 200, resp.StatusCode) header := resp.Header.Get("Content-Type") + require.Equal(t, "Accept", resp.Header.Get("Vary")) require.Equal(t, mediaTypeJSON, header) body, err := io.ReadAll(resp.Body) @@ -290,6 +365,7 @@ func TestPeers(t *testing.T) { require.Equal(t, 200, resp.StatusCode) header := resp.Header.Get("Content-Type") + require.Equal(t, "Accept", resp.Header.Get("Vary")) require.Equal(t, mediaTypeNDJSON, header) body, err := io.ReadAll(resp.Body) @@ -306,10 +382,8 @@ func makeName(t *testing.T) (crypto.PrivKey, ipns.Name) { return sk, ipns.NameFromPeer(pid) } -func makeIPNSRecord(t *testing.T, cid cid.Cid, sk crypto.PrivKey, opts ...ipns.Option) (*ipns.Record, []byte) { +func makeIPNSRecord(t *testing.T, cid cid.Cid, eol time.Time, ttl time.Duration, sk crypto.PrivKey, opts ...ipns.Option) (*ipns.Record, []byte) { path := path.FromCid(cid) - eol := time.Now().Add(time.Hour * 48) - ttl := time.Second * 20 record, err := ipns.NewRecord(sk, path, 1, eol, ttl, opts...) require.NoError(t, err) @@ -339,7 +413,18 @@ func TestIPNS(t *testing.T) { runWithRecordOptions := func(t *testing.T, opts ...ipns.Option) { sk, name1 := makeName(t) - record1, rawRecord1 := makeIPNSRecord(t, cid1, sk) + now := time.Now() + eol := now.Add(24 * time.Hour * 7) // record valid for a week + ttl := 42 * time.Second // distinct TTL + record1, rawRecord1 := makeIPNSRecord(t, cid1, eol, ttl, sk) + + stringToDuration := func(s string) time.Duration { + seconds, err := strconv.Atoi(s) + if err != nil { + return 0 + } + return time.Duration(seconds) * time.Second + } _, name2 := makeName(t) @@ -355,8 +440,25 @@ func TestIPNS(t *testing.T) { resp := makeRequest(t, router, "/routing/v1/ipns/"+name1.String()) require.Equal(t, 200, resp.StatusCode) require.Equal(t, mediaTypeIPNSRecord, resp.Header.Get("Content-Type")) + require.Equal(t, "Accept", resp.Header.Get("Vary")) require.NotEmpty(t, resp.Header.Get("Etag")) - require.Equal(t, "max-age=20", resp.Header.Get("Cache-Control")) + + requireCloseToNow(t, resp.Header.Get("Last-Modified")) + + require.Contains(t, resp.Header.Get("Cache-Control"), "public, max-age=42") + + // expected "stale" values are int(time.Until(eol).Seconds()) + // but running test on slow machine may be off by a few seconds + // and we need to assert with some room for drift (1 minute just to not break any CI) + re := regexp.MustCompile(`(?:^|,\s*)(max-age|stale-while-revalidate|stale-if-error)=(\d+)`) + matches := re.FindAllStringSubmatch(resp.Header.Get("Cache-Control"), -1) + staleWhileRevalidate := stringToDuration(matches[1][2]) + staleWhileError := stringToDuration(matches[2][2]) + require.WithinDuration(t, eol, time.Now().Add(staleWhileRevalidate), 1*time.Minute) + require.WithinDuration(t, eol, time.Now().Add(staleWhileError), 1*time.Minute) + + // 'Expires' on IPNS result is expected to match EOL of IPNS Record with ValidityType=0 + require.Equal(t, eol.UTC().Format(http.TimeFormat), resp.Header.Get("Expires")) body, err := io.ReadAll(resp.Body) require.NoError(t, err) diff --git a/routing/http/types/json/responses.go b/routing/http/types/json/responses.go index cc687df48..d8f659ac5 100644 --- a/routing/http/types/json/responses.go +++ b/routing/http/types/json/responses.go @@ -11,11 +11,19 @@ type ProvidersResponse struct { Providers RecordsArray } +func (r ProvidersResponse) Length() int { + return len(r.Providers) +} + // PeersResponse is the result of a GET Peers request. type PeersResponse struct { Peers []*types.PeerRecord } +func (r PeersResponse) Length() int { + return len(r.Peers) +} + // RecordsArray is an array of [types.Record] type RecordsArray []types.Record @@ -65,6 +73,10 @@ type WriteProvidersResponse struct { ProvideResults []types.Record } +func (r WriteProvidersResponse) Length() int { + return len(r.ProvideResults) +} + func (r *WriteProvidersResponse) UnmarshalJSON(b []byte) error { var tempWPR struct{ ProvideResults []json.RawMessage } err := json.Unmarshal(b, &tempWPR) From 25dd5a938efb08d45ae4ab9a5c0270fbda08c027 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Fri, 8 Mar 2024 14:09:58 +0100 Subject: [PATCH 04/12] chore: go 1.21 --- examples/go.mod | 2 +- examples/go.sum | 28 ++++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 22 ++++++++++++++++++++++ 4 files changed, 52 insertions(+), 2 deletions(-) diff --git a/examples/go.mod b/examples/go.mod index 6c0630543..93f0d9202 100644 --- a/examples/go.mod +++ b/examples/go.mod @@ -1,6 +1,6 @@ module github.com/ipfs/boxo/examples -go 1.20 +go 1.21 require ( github.com/ipfs/boxo v0.13.1 diff --git a/examples/go.sum b/examples/go.sum index cfb0944d0..e1ba68120 100644 --- a/examples/go.sum +++ b/examples/go.sum @@ -49,6 +49,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -72,6 +73,7 @@ github.com/flynn/noise v1.0.1/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwU github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= @@ -97,6 +99,7 @@ github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -123,6 +126,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= @@ -139,7 +143,9 @@ github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c h1:7lF+Vz0LqiRidnzC1Oq86fpX1q/iEv2KJdrCtttYjT4= +github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= @@ -164,6 +170,7 @@ github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= github.com/ipfs/go-blockservice v0.5.0 h1:B2mwhhhVQl2ntW2EIpaWPwSCxSuqr5fFA93Ms4bYLEY= +github.com/ipfs/go-blockservice v0.5.0/go.mod h1:W6brZ5k20AehbmERplmERn8o2Ni3ZZubvAxaIUeaT6w= github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= @@ -172,13 +179,19 @@ github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8 github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ipfs-blockstore v1.3.0 h1:m2EXaWgwTzAfsmt5UdJ7Is6l4gJcaM/A12XwJyvYvMM= +github.com/ipfs/go-ipfs-blockstore v1.3.0/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= +github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= +github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= +github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= github.com/ipfs/go-ipfs-exchange-interface v0.2.0 h1:8lMSJmKogZYNo2jjhUs0izT+dck05pqUw4mWNW9Pw6Y= +github.com/ipfs/go-ipfs-exchange-interface v0.2.0/go.mod h1:z6+RhJuDQbqKguVyslSOuVDhqF9JtTrO3eptSAiW2/Y= github.com/ipfs/go-ipfs-exchange-offline v0.3.0 h1:c/Dg8GDPzixGd0MC8Jh6mjOwU57uYokgWRFidfvEkuA= +github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB02e++Z7521fMxqCNRrz9s= github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE= github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4= github.com/ipfs/go-ipfs-redirects-file v0.1.1 h1:Io++k0Vf/wK+tfnhEh63Yte1oQK5VGT2hIEYpD0Rzx8= @@ -197,14 +210,17 @@ github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Ax github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-merkledag v0.11.0 h1:DgzwK5hprESOzS4O1t/wi6JDpyVQdvm9Bs59N/jqfBY= +github.com/ipfs/go-merkledag v0.11.0/go.mod h1:Q4f/1ezvBiJV0YCIXvt51W/9/kqJGH4I1LsA7+djsM4= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= github.com/ipfs/go-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg= github.com/ipfs/go-peertaskqueue v0.8.1/go.mod h1:Oxxd3eaK279FxeydSPPVGHzbwVeHjatZ2GA8XD+KbPU= github.com/ipfs/go-unixfs v0.4.5 h1:wj8JhxvV1G6CD7swACwSKYa+NgtdWC1RUit+gFnymDU= +github.com/ipfs/go-unixfs v0.4.5/go.mod h1:BIznJNvt/gEx/ooRMI4Us9K8+qeGO7vx1ohnbk8gjFg= github.com/ipfs/go-unixfsnode v1.9.0 h1:ubEhQhr22sPAKO2DNsyVBW7YB/zA8Zkif25aBvz8rc8= github.com/ipfs/go-unixfsnode v1.9.0/go.mod h1:HxRu9HYHOjK6HUqFBAi++7DVoWAHn0o4v/nZ/VA+0g8= github.com/ipfs/go-verifcid v0.0.2 h1:XPnUv0XmdH+ZIhLGKg6U2vaPaRDXb9urMyNVCE7uvTs= +github.com/ipfs/go-verifcid v0.0.2/go.mod h1:40cD9x1y4OWnFXbLNJYRe7MpNvWlMn3LZAG5Wb4xnPU= github.com/ipld/go-car/v2 v2.13.1 h1:KnlrKvEPEzr5IZHKTXLAEub+tPrzeAFQVRlSQvuxBO4= github.com/ipld/go-car/v2 v2.13.1/go.mod h1:QkdjjFNGit2GIkpQ953KBwowuoukoM75nP/JI1iDJdo= github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6rOcc= @@ -212,6 +228,7 @@ github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYt github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E= github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo= +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd/go.mod h1:wZ8hH8UxeryOs4kJEJaiui/s00hDSbE37OKsL47g+Sw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.1.0/go.mod h1:TqNnHUmJgXau0nCzC7kXWeotg3J9W34CUv5Djy1+FlA= @@ -236,10 +253,12 @@ github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoK github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= @@ -261,6 +280,7 @@ github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvN github.com/libp2p/go-libp2p-routing-helpers v0.7.3 h1:u1LGzAMVRK9Nqq5aYDVOiq/HaB93U9WWczBzGyAC5ZY= github.com/libp2p/go-libp2p-routing-helpers v0.7.3/go.mod h1:cN4mJAD/7zfPKXBcs9ze31JGYAZgzdABEm+q/hkswb8= github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= +github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= @@ -337,6 +357,7 @@ github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -381,6 +402,7 @@ github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtB github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= @@ -434,6 +456,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb h1:Ywfo8sUltxogBpFuMOFRrrSifO788kAFxmvVw31PtQQ= github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -441,6 +464,7 @@ github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60Nt github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s= +github.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= @@ -494,12 +518,14 @@ go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v8 go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk= go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -644,6 +670,7 @@ google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= +google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo= google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4= @@ -681,6 +708,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/go.mod b/go.mod index 9f9cb9424..b3aa064e4 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/ipfs/boxo -go 1.20 +go 1.21 require ( github.com/alecthomas/units v0.0.0-20231202071711-9a357b53e9c9 diff --git a/go.sum b/go.sum index 50e780682..7f79ac4fb 100644 --- a/go.sum +++ b/go.sum @@ -49,6 +49,7 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -70,6 +71,7 @@ github.com/flynn/noise v1.0.1/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwU github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= @@ -123,6 +125,7 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= @@ -169,6 +172,7 @@ github.com/ipfs/go-block-format v0.0.2/go.mod h1:AWR46JfpcObNfg3ok2JHDUfdiHRgWhJ github.com/ipfs/go-block-format v0.2.0 h1:ZqrkxBA2ICbDRbK8KJs/u0O3dlp6gmAuuXUJNiW1Ycs= github.com/ipfs/go-block-format v0.2.0/go.mod h1:+jpL11nFx5A/SPpsoBn6Bzkra/zaArfSmsknbPMYgzM= github.com/ipfs/go-blockservice v0.5.0 h1:B2mwhhhVQl2ntW2EIpaWPwSCxSuqr5fFA93Ms4bYLEY= +github.com/ipfs/go-blockservice v0.5.0/go.mod h1:W6brZ5k20AehbmERplmERn8o2Ni3ZZubvAxaIUeaT6w= github.com/ipfs/go-cid v0.0.1/go.mod h1:GHWU/WuQdMPmIosc4Yn1bcCT7dSeX4lBafM7iqUPQvM= github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I= github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= @@ -180,14 +184,19 @@ github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8 github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk= github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps= github.com/ipfs/go-ipfs-blockstore v1.3.0 h1:m2EXaWgwTzAfsmt5UdJ7Is6l4gJcaM/A12XwJyvYvMM= +github.com/ipfs/go-ipfs-blockstore v1.3.0/go.mod h1:KgtZyc9fq+P2xJUiCAzbRdhhqJHvsw8u2Dlqy2MyRTE= github.com/ipfs/go-ipfs-blocksutil v0.0.1 h1:Eh/H4pc1hsvhzsQoMEP3Bke/aW5P5rVM1IWFJMcGIPQ= github.com/ipfs/go-ipfs-blocksutil v0.0.1/go.mod h1:Yq4M86uIOmxmGPUHv/uI7uKqZNtLb449gwKqXjIsnRk= github.com/ipfs/go-ipfs-chunker v0.0.5 h1:ojCf7HV/m+uS2vhUGWcogIIxiO5ubl5O57Q7NapWLY8= +github.com/ipfs/go-ipfs-chunker v0.0.5/go.mod h1:jhgdF8vxRHycr00k13FM8Y0E+6BoalYeobXmUyTreP8= github.com/ipfs/go-ipfs-delay v0.0.1 h1:r/UXYyRcddO6thwOnhiznIAiSvxMECGgtv35Xs1IeRQ= github.com/ipfs/go-ipfs-delay v0.0.1/go.mod h1:8SP1YXK1M1kXuc4KJZINY3TQQ03J2rwBG9QfXmbRPrw= github.com/ipfs/go-ipfs-ds-help v1.1.0 h1:yLE2w9RAsl31LtfMt91tRZcrx+e61O5mDxFRR994w4Q= +github.com/ipfs/go-ipfs-ds-help v1.1.0/go.mod h1:YR5+6EaebOhfcqVCyqemItCLthrpVNot+rsOU/5IatU= github.com/ipfs/go-ipfs-exchange-interface v0.2.0 h1:8lMSJmKogZYNo2jjhUs0izT+dck05pqUw4mWNW9Pw6Y= +github.com/ipfs/go-ipfs-exchange-interface v0.2.0/go.mod h1:z6+RhJuDQbqKguVyslSOuVDhqF9JtTrO3eptSAiW2/Y= github.com/ipfs/go-ipfs-exchange-offline v0.3.0 h1:c/Dg8GDPzixGd0MC8Jh6mjOwU57uYokgWRFidfvEkuA= +github.com/ipfs/go-ipfs-exchange-offline v0.3.0/go.mod h1:MOdJ9DChbb5u37M1IcbrRB02e++Z7521fMxqCNRrz9s= github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE= github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4= github.com/ipfs/go-ipfs-redirects-file v0.1.1 h1:Io++k0Vf/wK+tfnhEh63Yte1oQK5VGT2hIEYpD0Rzx8= @@ -207,6 +216,7 @@ github.com/ipfs/go-log/v2 v2.1.3/go.mod h1:/8d0SH3Su5Ooc31QlL1WysJhvyOTDCjcCZ9Ax github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= github.com/ipfs/go-merkledag v0.11.0 h1:DgzwK5hprESOzS4O1t/wi6JDpyVQdvm9Bs59N/jqfBY= +github.com/ipfs/go-merkledag v0.11.0/go.mod h1:Q4f/1ezvBiJV0YCIXvt51W/9/kqJGH4I1LsA7+djsM4= github.com/ipfs/go-metrics-interface v0.0.1 h1:j+cpbjYvu4R8zbleSs36gvB7jR+wsL2fGD6n0jO4kdg= github.com/ipfs/go-metrics-interface v0.0.1/go.mod h1:6s6euYU4zowdslK0GKHmqaIZ3j/b/tL7HTWtJ4VPgWY= github.com/ipfs/go-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg= @@ -216,6 +226,7 @@ github.com/ipfs/go-unixfs v0.4.5/go.mod h1:BIznJNvt/gEx/ooRMI4Us9K8+qeGO7vx1ohnb github.com/ipfs/go-unixfsnode v1.9.0 h1:ubEhQhr22sPAKO2DNsyVBW7YB/zA8Zkif25aBvz8rc8= github.com/ipfs/go-unixfsnode v1.9.0/go.mod h1:HxRu9HYHOjK6HUqFBAi++7DVoWAHn0o4v/nZ/VA+0g8= github.com/ipfs/go-verifcid v0.0.2 h1:XPnUv0XmdH+ZIhLGKg6U2vaPaRDXb9urMyNVCE7uvTs= +github.com/ipfs/go-verifcid v0.0.2/go.mod h1:40cD9x1y4OWnFXbLNJYRe7MpNvWlMn3LZAG5Wb4xnPU= github.com/ipld/go-car/v2 v2.13.1 h1:KnlrKvEPEzr5IZHKTXLAEub+tPrzeAFQVRlSQvuxBO4= github.com/ipld/go-car/v2 v2.13.1/go.mod h1:QkdjjFNGit2GIkpQ953KBwowuoukoM75nP/JI1iDJdo= github.com/ipld/go-codec-dagpb v1.6.0 h1:9nYazfyu9B1p3NAgfVdpRco3Fs2nFC72DqVsMj6rOcc= @@ -223,6 +234,7 @@ github.com/ipld/go-codec-dagpb v1.6.0/go.mod h1:ANzFhfP2uMJxRBr8CE+WQWs5UsNa0pYt github.com/ipld/go-ipld-prime v0.21.0 h1:n4JmcpOlPDIxBcY037SVfpd1G+Sj1nKZah0m6QH9C2E= github.com/ipld/go-ipld-prime v0.21.0/go.mod h1:3RLqy//ERg/y5oShXXdx5YIp50cFGOanyMctpPjsvxQ= github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd h1:gMlw/MhNr2Wtp5RwGdsW23cs+yCuj9k2ON7i9MiJlRo= +github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20230102063945-1a409dc236dd/go.mod h1:wZ8hH8UxeryOs4kJEJaiui/s00hDSbE37OKsL47g+Sw= github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= github.com/jbenet/go-cienv v0.1.0 h1:Vc/s0QbQtoxX8MwwSLWWh+xNNZvM3Lw7NsTcHrvvhMc= @@ -248,10 +260,12 @@ github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoK github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= github.com/libp2p/go-cidranger v1.1.0 h1:ewPN8EZ0dd1LSnrtuwd4709PXVcITVeuwbag38yPW7c= @@ -353,6 +367,7 @@ github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs= github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM= github.com/onsi/gomega v1.29.0 h1:KIA/t2t5UBzoirT4H9tsML45GEbo3ouUnBHsCfD2tVg= +github.com/onsi/gomega v1.29.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.1.0 h1:HHUyrt9mwHUjtasSbXSMvs4cyFxh+Bll4AjJ9odEGpg= github.com/opencontainers/runtime-spec v1.1.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -397,6 +412,7 @@ github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtB github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= +github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= @@ -450,6 +466,7 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= github.com/tj/assert v0.0.3 h1:Df/BlaZ20mq6kuai7f5z2TvPFiwC3xaWJSDQNiIS3Rk= +github.com/tj/assert v0.0.3/go.mod h1:Ne6X72Q+TB1AteidzQncjw9PabbMp4PBMZ1k+vd1Pvk= github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb h1:Ywfo8sUltxogBpFuMOFRrrSifO788kAFxmvVw31PtQQ= github.com/ucarion/urlpath v0.0.0-20200424170820-7ccc79b76bbb/go.mod h1:ikPs9bRWicNw3S7XpJ8sK/smGwU9WcSVU3dy9qahYBM= github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= @@ -457,6 +474,7 @@ github.com/urfave/cli v1.22.10/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60Nt github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= github.com/warpfork/go-testmark v0.12.1 h1:rMgCpJfwy1sJ50x0M0NgyphxYYPMOODIJHhsXyEHU0s= +github.com/warpfork/go-testmark v0.12.1/go.mod h1:kHwy7wfvGSPh1rQJYKayD4AbtNaeyZdcGi9tNJTaa5Y= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0 h1:GDDkbFiaK8jsSDJfjId/PEGEShv6ugrt4kYsC5UIDaQ= github.com/warpfork/go-wish v0.0.0-20220906213052-39a1cc7a02d0/go.mod h1:x6AKhvSSexNrVSrViXSHUEbICjmGXhtgABaHIySUSGw= github.com/whyrusleeping/base32 v0.0.0-20170828182744-c30ac30633cc h1:BCPnHtcboadS0DvysUuJXZ4lWVv5Bh5i7+tbIyi+ck4= @@ -499,12 +517,14 @@ go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v8 go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= go.uber.org/fx v1.20.1 h1:zVwVQGS8zYvhh9Xxcu4w1M6ESyeMzebzj2NbSayZ4Mk= go.uber.org/fx v1.20.1/go.mod h1:iSYNbHf2y55acNCwCXKx7LbWb5WG1Bnue5RDXz1OREg= go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= +go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= @@ -666,6 +686,7 @@ google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRn google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917 h1:nz5NESFLZbJGPFxDT/HCn+V1mZ8JGNoY4nUpmW/Y2eg= +google.golang.org/genproto v0.0.0-20240102182953-50ed04b92917/go.mod h1:pZqR+glSb11aJ+JQcczCvgf47+duRuzNSKqE8YAQnV0= google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1 h1:OPXtXn7fNMaXwO3JvOmF1QyTc00jsSFFz1vXXBOdCDo= google.golang.org/genproto/googleapis/api v0.0.0-20240108191215-35c7eff3a6b1/go.mod h1:B5xPO//w8qmBDjGReYLpR6UJPnkldGkCSMoH/2vxJeg= google.golang.org/genproto/googleapis/rpc v0.0.0-20240108191215-35c7eff3a6b1 h1:gphdwh0npgs8elJ4T6J+DQJHPVF7RsuJHCfwztUb4J4= @@ -703,6 +724,7 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= From 2559ec2c7b93ac6905fe83d7a4b38b8e9a703b0a Mon Sep 17 00:00:00 2001 From: web3-bot Date: Thu, 14 Mar 2024 02:07:08 +0100 Subject: [PATCH 05/12] ci: uci/update-go (#589) * chore: bump go.mod to Go 1.21 and run go fix * chore: run go mod tidy * chore: bump go.mod to Go 1.21 and run go fix * chore: run go mod tidy * chore: CHANGELOG.md --------- Co-authored-by: Marcin Rataj --- CHANGELOG.md | 2 ++ cmd/boxo-migrate/go.mod | 2 +- cmd/deprecator/go.mod | 2 +- cmd/deprecator/go.sum | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecf1ffe2a..a76d9aab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,8 @@ The following emojis are used to highlight certain changes: ### Changed +* `go` version changed to 1.21 + ### Removed ### Fixed diff --git a/cmd/boxo-migrate/go.mod b/cmd/boxo-migrate/go.mod index 71f42ac9c..69808ef1d 100644 --- a/cmd/boxo-migrate/go.mod +++ b/cmd/boxo-migrate/go.mod @@ -1,6 +1,6 @@ module github.com/ipfs/boxo/cmd/boxo-migrate -go 1.20 +go 1.21 require github.com/urfave/cli/v2 v2.25.1 diff --git a/cmd/deprecator/go.mod b/cmd/deprecator/go.mod index c68dd5412..666865084 100644 --- a/cmd/deprecator/go.mod +++ b/cmd/deprecator/go.mod @@ -1,6 +1,6 @@ module github.com/ipfs/boxo/cmd/deprecator -go 1.20 +go 1.21 require ( github.com/dave/dst v0.27.2 diff --git a/cmd/deprecator/go.sum b/cmd/deprecator/go.sum index 92bdc5769..63ff39864 100644 --- a/cmd/deprecator/go.sum +++ b/cmd/deprecator/go.sum @@ -3,9 +3,11 @@ github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/dave/dst v0.27.2 h1:4Y5VFTkhGLC1oddtNwuxxe36pnyLxMFXT51FOzH8Ekc= github.com/dave/dst v0.27.2/go.mod h1:jHh6EOibnHgcUW3WjKHisiooEkYwqpHLBSX1iOBhEyc= github.com/dave/jennifer v1.5.0 h1:HmgPN93bVDpkQyYbqhCHj5QlgvUkvEOzMyEvKLgCRrg= +github.com/dave/jennifer v1.5.0/go.mod h1:4MnyiFIlZS3l5tSDn8VnzE6ffAhYBMB2SZntBsZGUok= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= +github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/urfave/cli/v2 v2.25.3 h1:VJkt6wvEBOoSjPFQvOkv6iWIrsJyCrKGtCtxXWwmGeY= github.com/urfave/cli/v2 v2.25.3/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= From bff10de82878e1c215dba79c5ee037dcac5c0c08 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Wed, 6 Mar 2024 11:37:22 +0100 Subject: [PATCH 06/12] ipns: fix test by using global random reader --- ipns/record_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipns/record_test.go b/ipns/record_test.go index db92a6a17..6ab1d5994 100644 --- a/ipns/record_test.go +++ b/ipns/record_test.go @@ -2,6 +2,7 @@ package ipns import ( "bytes" + "crypto/rand" "testing" "time" @@ -30,8 +31,7 @@ func init() { } func mustKeyPair(t *testing.T, typ int) (ic.PrivKey, ic.PubKey, Name) { - sr := util.NewTimeSeededRand() - sk, pk, err := ic.GenerateKeyPairWithReader(typ, 2048, sr) + sk, pk, err := ic.GenerateKeyPairWithReader(typ, 2048, rand.Reader) require.NoError(t, err) pid, err := peer.IDFromPublicKey(pk) From b101ba0858150cd6a34b6cb68eefd28c411bd58c Mon Sep 17 00:00:00 2001 From: web3-bot Date: Fri, 22 Mar 2024 08:34:08 +0000 Subject: [PATCH 07/12] ci: uci/copy-templates (#590) --- .github/workflows/go-check.yml | 2 +- .github/workflows/go-test.yml | 4 +++- .github/workflows/release-check.yml | 2 +- .github/workflows/releaser.yml | 2 +- .github/workflows/tagpush.yml | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/go-check.yml b/.github/workflows/go-check.yml index 9c0589c07..ee5507d08 100644 --- a/.github/workflows/go-check.yml +++ b/.github/workflows/go-check.yml @@ -15,4 +15,4 @@ concurrency: jobs: go-check: - uses: pl-strflt/uci/.github/workflows/go-check.yml@v0.0 + uses: ipdxco/unified-github-workflows/.github/workflows/go-check.yml@v1.0 diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index f9d7cb34d..f8e8e8048 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -15,4 +15,6 @@ concurrency: jobs: go-test: - uses: ipfs/uci/.github/workflows/go-test.yml@v0.0 + uses: ipfs/uci/.github/workflows/go-test.yml@v1.0 + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/release-check.yml b/.github/workflows/release-check.yml index bda616005..0b5ff6070 100644 --- a/.github/workflows/release-check.yml +++ b/.github/workflows/release-check.yml @@ -16,4 +16,4 @@ concurrency: jobs: release-check: - uses: pl-strflt/uci/.github/workflows/release-check.yml@v0.0 + uses: ipdxco/unified-github-workflows/.github/workflows/release-check.yml@v1.0 diff --git a/.github/workflows/releaser.yml b/.github/workflows/releaser.yml index dd8081b91..2ebdbed31 100644 --- a/.github/workflows/releaser.yml +++ b/.github/workflows/releaser.yml @@ -14,4 +14,4 @@ concurrency: jobs: releaser: - uses: pl-strflt/uci/.github/workflows/releaser.yml@v0.0 + uses: ipdxco/unified-github-workflows/.github/workflows/releaser.yml@v1.0 diff --git a/.github/workflows/tagpush.yml b/.github/workflows/tagpush.yml index 59de8cb91..5ef3fb9ed 100644 --- a/.github/workflows/tagpush.yml +++ b/.github/workflows/tagpush.yml @@ -15,4 +15,4 @@ concurrency: jobs: releaser: - uses: pl-strflt/uci/.github/workflows/tagpush.yml@v0.0 + uses: ipdxco/unified-github-workflows/.github/workflows/tagpush.yml@v1.0 From 3a31820fcfb8d53766e77aa712e7f99c26cbfabe Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Fri, 5 Apr 2024 09:31:43 +0200 Subject: [PATCH 08/12] feat(routing/http/server): improve ux of /ipns (#596) --- CHANGELOG.md | 1 + routing/http/server/server.go | 16 +++- routing/http/server/server_test.go | 124 ++++++++++++++++++++++++++--- 3 files changed, 130 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a76d9aab4..49cb65a55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The following emojis are used to highlight certain changes: ### Added * `routing/http/server` now adds `Cache-Control` HTTP header to GET requests: 15 seconds for empty responses, or 5 minutes for responses with providers. +* `routing/http/server` the `/ipns` endpoint is more friendly to users opening URL in web browsers: returns `Content-Disposition` header and defaults to `application/vnd.ipfs.ipns-record` response when `Accept` is missing. ### Changed diff --git a/routing/http/server/server.go b/routing/http/server/server.go index b00f22012..ebc9b24e0 100644 --- a/routing/http/server/server.go +++ b/routing/http/server/server.go @@ -22,6 +22,7 @@ import ( "github.com/ipfs/go-cid" "github.com/libp2p/go-libp2p/core/peer" "github.com/multiformats/go-multiaddr" + "github.com/multiformats/go-multibase" logging "github.com/ipfs/go-log/v2" ) @@ -370,8 +371,14 @@ func (s *server) findPeersNDJSON(w http.ResponseWriter, peersIter iter.ResultIte } func (s *server) GetIPNS(w http.ResponseWriter, r *http.Request) { - if !strings.Contains(r.Header.Get("Accept"), mediaTypeIPNSRecord) { - writeErr(w, "GetIPNS", http.StatusNotAcceptable, errors.New("content type in 'Accept' header is missing or not supported")) + acceptHdrValue := r.Header.Get("Accept") + // When 'Accept' header is missing, default to 'application/vnd.ipfs.ipns-record' + // (improved UX, similar to how we default to JSON response for /providers and /peers) + if len(acceptHdrValue) == 0 || strings.Contains(acceptHdrValue, mediaTypeWildcard) { + acceptHdrValue = mediaTypeIPNSRecord + } + if !strings.Contains(acceptHdrValue, mediaTypeIPNSRecord) { + writeErr(w, "GetIPNS", http.StatusNotAcceptable, errors.New("content type in 'Accept' header is not supported, retry with 'application/vnd.ipfs.ipns-record'")) return } @@ -420,6 +427,11 @@ func (s *server) GetIPNS(w http.ResponseWriter, r *http.Request) { w.Header().Set("Etag", fmt.Sprintf(`"%x"`, xxhash.Sum64(rawRecord))) w.Header().Set("Content-Type", mediaTypeIPNSRecord) + + // Content-Disposition is not required, but improves UX by assigning a meaningful filename when opening URL in a web browser + if filename, err := cid.StringOfBase(multibase.Base36); err == nil { + w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s.ipns-record\"", filename)) + } w.Header().Add("Vary", "Accept") w.Write(rawRecord) } diff --git a/routing/http/server/server_test.go b/routing/http/server/server_test.go index ea827000f..3b2a23453 100644 --- a/routing/http/server/server_test.go +++ b/routing/http/server/server_test.go @@ -9,6 +9,7 @@ import ( "net/http/httptest" "regexp" "strconv" + "strings" "testing" "time" @@ -128,7 +129,14 @@ func TestProviders(t *testing.T) { req, err := http.NewRequest(http.MethodGet, urlStr, nil) require.NoError(t, err) - req.Header.Set("Accept", contentType) + + if contentType == "" || strings.Contains(contentType, mediaTypeWildcard) { + // When no Accept header is provided with request + // we default expected response to JSON + contentType = mediaTypeJSON + } else { + req.Header.Set("Accept", contentType) + } resp, err := http.DefaultClient.Do(req) require.NoError(t, err) @@ -158,6 +166,16 @@ func TestProviders(t *testing.T) { runTest(t, mediaTypeJSON, true, false, `{"Providers":null}`) }) + t.Run("Wildcard Accept header defaults to JSON Response", func(t *testing.T) { + accept := "text/html,*/*" + runTest(t, accept, true, false, `{"Providers":null}`) + }) + + t.Run("Missing Accept header defaults to JSON Response", func(t *testing.T) { + accept := "" + runTest(t, accept, true, false, `{"Providers":null}`) + }) + t.Run("NDJSON Response", func(t *testing.T) { runTest(t, mediaTypeNDJSON, false, true, `{"Addrs":[],"ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vn","Protocols":["transport-bitswap"],"Schema":"peer"}`+"\n"+`{"Schema":"bitswap","Protocol":"transport-bitswap","ID":"12D3KooWM8sovaEGU1bmiWGWAzvs47DEcXKZZTuJnpQyVTkRs2Vz"}`+"\n") }) @@ -173,7 +191,9 @@ func TestPeers(t *testing.T) { t.Cleanup(server.Close) req, err := http.NewRequest(http.MethodGet, "http://"+server.Listener.Addr().String()+"/routing/v1/peers/"+arg, nil) require.NoError(t, err) - req.Header.Set("Accept", contentType) + if contentType != "" { + req.Header.Set("Accept", contentType) + } resp, err := http.DefaultClient.Do(req) require.NoError(t, err) return resp @@ -187,7 +207,7 @@ func TestPeers(t *testing.T) { require.Equal(t, 400, resp.StatusCode) }) - t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body and headers (No Results, JSON)", func(t *testing.T) { + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body and headers (No Results, explicit JSON)", func(t *testing.T) { t.Parallel() _, pid := makePeerID(t) @@ -206,6 +226,42 @@ func TestPeers(t *testing.T) { requireCloseToNow(t, resp.Header.Get("Last-Modified")) }) + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body and headers (No Results, implicit JSON, wildcard Accept header)", func(t *testing.T) { + t.Parallel() + + _, pid := makePeerID(t) + results := iter.FromSlice([]iter.Result[*types.PeerRecord]{}) + + router := &mockContentRouter{} + router.On("FindPeers", mock.Anything, pid, 20).Return(results, nil) + + // Simulate request with Accept header that includes wildcard match + resp := makeRequest(t, router, "text/html,*/*", peer.ToCid(pid).String()) + + // Expect response to default to application/json + require.Equal(t, 200, resp.StatusCode) + require.Equal(t, mediaTypeJSON, resp.Header.Get("Content-Type")) + + }) + + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body and headers (No Results, implicit JSON, no Accept header)", func(t *testing.T) { + t.Parallel() + + _, pid := makePeerID(t) + results := iter.FromSlice([]iter.Result[*types.PeerRecord]{}) + + router := &mockContentRouter{} + router.On("FindPeers", mock.Anything, pid, 20).Return(results, nil) + + // Simulate request without Accept header + resp := makeRequest(t, router, "", peer.ToCid(pid).String()) + + // Expect response to default to application/json + require.Equal(t, 200, resp.StatusCode) + require.Equal(t, mediaTypeJSON, resp.Header.Get("Content-Type")) + + }) + t.Run("GET /routing/v1/peers/{cid-libp2p-key-peer-id} returns 200 with correct body and headers (JSON)", func(t *testing.T) { t.Parallel() @@ -398,14 +454,16 @@ func TestIPNS(t *testing.T) { cid1, err := cid.Decode("bafkreifjjcie6lypi6ny7amxnfftagclbuxndqonfipmb64f2km2devei4") require.NoError(t, err) - makeRequest := func(t *testing.T, router *mockContentRouter, path string) *http.Response { + makeRequest := func(t *testing.T, router *mockContentRouter, path string, accept string) *http.Response { server := httptest.NewServer(Handler(router)) t.Cleanup(server.Close) serverAddr := "http://" + server.Listener.Addr().String() urlStr := serverAddr + path req, err := http.NewRequest(http.MethodGet, urlStr, nil) require.NoError(t, err) - req.Header.Set("Accept", mediaTypeIPNSRecord) + if accept != "" { + req.Header.Set("Accept", accept) + } resp, err := http.DefaultClient.Do(req) require.NoError(t, err) return resp @@ -428,7 +486,7 @@ func TestIPNS(t *testing.T) { _, name2 := makeName(t) - t.Run("GET /routing/v1/ipns/{cid-peer-id} returns 200", func(t *testing.T) { + t.Run("GET /routing/v1/ipns/{cid-peer-id} returns 200 (explicit Accept header)", func(t *testing.T) { t.Parallel() rec, err := ipns.UnmarshalRecord(rawRecord1) @@ -437,7 +495,7 @@ func TestIPNS(t *testing.T) { router := &mockContentRouter{} router.On("GetIPNS", mock.Anything, name1).Return(rec, nil) - resp := makeRequest(t, router, "/routing/v1/ipns/"+name1.String()) + resp := makeRequest(t, router, "/routing/v1/ipns/"+name1.String(), mediaTypeIPNSRecord) require.Equal(t, 200, resp.StatusCode) require.Equal(t, mediaTypeIPNSRecord, resp.Header.Get("Content-Type")) require.Equal(t, "Accept", resp.Header.Get("Vary")) @@ -445,6 +503,8 @@ func TestIPNS(t *testing.T) { requireCloseToNow(t, resp.Header.Get("Last-Modified")) + require.Contains(t, resp.Header.Get("Content-Disposition"), `attachment; filename="`+name1.String()+`.ipns-record"`) + require.Contains(t, resp.Header.Get("Cache-Control"), "public, max-age=42") // expected "stale" values are int(time.Until(eol).Seconds()) @@ -465,11 +525,57 @@ func TestIPNS(t *testing.T) { require.Equal(t, body, rawRecord1) }) + t.Run("GET /routing/v1/ipns/{cid-peer-id} returns 200 (Accept header missing)", func(t *testing.T) { + t.Parallel() + + rec, err := ipns.UnmarshalRecord(rawRecord1) + require.NoError(t, err) + + router := &mockContentRouter{} + router.On("GetIPNS", mock.Anything, name1).Return(rec, nil) + + // Simulate request without explicit Accept header + noAccept := "" + resp := makeRequest(t, router, "/routing/v1/ipns/"+name1.String(), noAccept) + + // Expect application/vnd.ipfs.ipns-record in response + require.Equal(t, 200, resp.StatusCode) + require.Equal(t, mediaTypeIPNSRecord, resp.Header.Get("Content-Type")) + + // Confirm body matches expected bytes + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, body, rawRecord1) + }) + + t.Run("GET /routing/v1/ipns/{cid-peer-id} returns 200 (Accept header with wildcard)", func(t *testing.T) { + t.Parallel() + + rec, err := ipns.UnmarshalRecord(rawRecord1) + require.NoError(t, err) + + router := &mockContentRouter{} + router.On("GetIPNS", mock.Anything, name1).Return(rec, nil) + + // Simulate request with wildcard Accept header + wcAccept := "text/html,*/*" + resp := makeRequest(t, router, "/routing/v1/ipns/"+name1.String(), wcAccept) + + // Expect application/vnd.ipfs.ipns-record in response + require.Equal(t, 200, resp.StatusCode) + require.Equal(t, mediaTypeIPNSRecord, resp.Header.Get("Content-Type")) + + // Confirm body matches expected bytes + body, err := io.ReadAll(resp.Body) + require.NoError(t, err) + require.Equal(t, body, rawRecord1) + }) + t.Run("GET /routing/v1/ipns/{non-peer-cid} returns 400", func(t *testing.T) { t.Parallel() router := &mockContentRouter{} - resp := makeRequest(t, router, "/routing/v1/ipns/"+cid1.String()) + resp := makeRequest(t, router, "/routing/v1/ipns/"+cid1.String(), mediaTypeIPNSRecord) require.Equal(t, 400, resp.StatusCode) }) @@ -477,7 +583,7 @@ func TestIPNS(t *testing.T) { t.Parallel() router := &mockContentRouter{} - resp := makeRequest(t, router, "/routing/v1/ipns/"+name1.Peer().String()) + resp := makeRequest(t, router, "/routing/v1/ipns/"+name1.Peer().String(), mediaTypeIPNSRecord) require.Equal(t, 400, resp.StatusCode) }) From 5fc25a40565e57e977ba3685f038ed630d2b79e6 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 9 Apr 2024 08:08:41 +0200 Subject: [PATCH 09/12] bitswap: add missing client options to exchange (#597) --- CHANGELOG.md | 1 + bitswap/options.go | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 49cb65a55..5114d3158 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ The following emojis are used to highlight certain changes: ### Fixed - 🛠️`routing/http/server`: delegated peer routing endpoint now supports both [PeerID string notaitons from libp2p specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation). +- `bitswap`: add missing client `WithBlockReceivedNotifier` and `WithoutDuplicatedBlockStats` options to the exchange. ### Security diff --git a/bitswap/options.go b/bitswap/options.go index da759dfe2..6cdcef5bd 100644 --- a/bitswap/options.go +++ b/bitswap/options.go @@ -79,6 +79,14 @@ func SetSimulateDontHavesOnTimeout(send bool) Option { return Option{client.SetSimulateDontHavesOnTimeout(send)} } +func WithBlockReceivedNotifier(brn client.BlockReceivedNotifier) Option { + return Option{client.WithBlockReceivedNotifier(brn)} +} + +func WithoutDuplicatedBlockStats() Option { + return Option{client.WithoutDuplicatedBlockStats()} +} + func WithTracer(tap tracer.Tracer) Option { // Only trace the server, both receive the same messages anyway return Option{ From ec207931045d1e40d56cb3a6e8b88e88d6888288 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 9 Apr 2024 08:28:00 +0200 Subject: [PATCH 10/12] provider: prioritize roots and introduce NewPrioritizedProvider (#595) --- CHANGELOG.md | 3 + provider/provider.go | 109 +++++++++++++++++++++++++++++------- provider/reprovider_test.go | 92 ++++++++++++++++++++++++++++++ 3 files changed, 183 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5114d3158..9c9fa7bb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ The following emojis are used to highlight certain changes: * `routing/http/server` now adds `Cache-Control` HTTP header to GET requests: 15 seconds for empty responses, or 5 minutes for responses with providers. * `routing/http/server` the `/ipns` endpoint is more friendly to users opening URL in web browsers: returns `Content-Disposition` header and defaults to `application/vnd.ipfs.ipns-record` response when `Accept` is missing. +* `provider`: + * Exports a `NewPrioritizedProvider`, which can be used to prioritize certain providers while ignoring duplicates. + * 🛠️ `NewPinnedProvider` now prioritizes root blocks, even if `onlyRoots` is set to `false`. ### Changed diff --git a/provider/provider.go b/provider/provider.go index 530469fc1..a20a805cb 100644 --- a/provider/provider.go +++ b/provider/provider.go @@ -71,45 +71,112 @@ func NewPinnedProvider(onlyRoots bool, pinning pin.Pinner, fetchConfig fetcher.F } func pinSet(ctx context.Context, pinning pin.Pinner, fetchConfig fetcher.Factory, onlyRoots bool) (*cidutil.StreamingSet, error) { - // FIXME: Listing all pins code is duplicated thrice, twice in Kubo and here, maybe more. - // If this were a method of the [pin.Pinner] life would be easier. set := cidutil.NewStreamingSet() + recursivePins := cidutil.NewSet() go func() { ctx, cancel := context.WithCancel(ctx) defer cancel() defer close(set.New) - for sc := range pinning.DirectKeys(ctx, false) { + // 1. Recursive keys + for sc := range pinning.RecursiveKeys(ctx, false) { if sc.Err != nil { - logR.Errorf("reprovide direct pins: %s", sc.Err) + logR.Errorf("reprovide recursive pins: %s", sc.Err) return } - set.Visitor(ctx)(sc.Pin.Key) + if !onlyRoots { + // Save some bytes. + _ = recursivePins.Visit(sc.Pin.Key) + } + _ = set.Visitor(ctx)(sc.Pin.Key) } - session := fetchConfig.NewSession(ctx) - for sc := range pinning.RecursiveKeys(ctx, false) { + // 2. Direct pins + for sc := range pinning.DirectKeys(ctx, false) { if sc.Err != nil { - logR.Errorf("reprovide recursive pins: %s", sc.Err) + logR.Errorf("reprovide direct pins: %s", sc.Err) return } - set.Visitor(ctx)(sc.Pin.Key) - if !onlyRoots { - err := fetcherhelpers.BlockAll(ctx, session, cidlink.Link{Cid: sc.Pin.Key}, func(res fetcher.FetchResult) error { - clink, ok := res.LastBlockLink.(cidlink.Link) - if ok { - set.Visitor(ctx)(clink.Cid) - } - return nil - }) - if err != nil { - logR.Errorf("reprovide indirect pins: %s", err) - return + _ = set.Visitor(ctx)(sc.Pin.Key) + } + + if onlyRoots { + return + } + + // 3. Go through recursive pins to fetch remaining blocks if we want more + // than just roots. + session := fetchConfig.NewSession(ctx) + err := recursivePins.ForEach(func(c cid.Cid) error { + return fetcherhelpers.BlockAll(ctx, session, cidlink.Link{Cid: c}, func(res fetcher.FetchResult) error { + clink, ok := res.LastBlockLink.(cidlink.Link) + if ok { + _ = set.Visitor(ctx)(clink.Cid) } - } + return nil + }) + }) + if err != nil { + logR.Errorf("reprovide indirect pins: %s", err) + return } }() return set, nil } + +func NewPrioritizedProvider(priorityCids KeyChanFunc, otherCids KeyChanFunc) KeyChanFunc { + return func(ctx context.Context) (<-chan cid.Cid, error) { + outCh := make(chan cid.Cid) + + go func() { + defer close(outCh) + visited := cidutil.NewSet() + + handleStream := func(stream KeyChanFunc, markVisited bool) error { + ch, err := stream(ctx) + if err != nil { + return err + } + + for { + select { + case <-ctx.Done(): + return nil + case c, ok := <-ch: + if !ok { + return nil + } + + if visited.Has(c) { + continue + } + + select { + case <-ctx.Done(): + return nil + case outCh <- c: + if markVisited { + _ = visited.Visit(c) + } + } + } + } + } + + err := handleStream(priorityCids, true) + if err != nil { + log.Warnf("error in prioritized strategy while handling priority CIDs: %w", err) + return + } + + err = handleStream(otherCids, false) + if err != nil { + log.Warnf("error in prioritized strategy while handling other CIDs: %w", err) + } + }() + + return outCh, nil + } +} diff --git a/provider/reprovider_test.go b/provider/reprovider_test.go index 4efd9bda1..4ae58148e 100644 --- a/provider/reprovider_test.go +++ b/provider/reprovider_test.go @@ -3,6 +3,7 @@ package provider import ( "bytes" "context" + "crypto/rand" "runtime" "strconv" "sync" @@ -15,6 +16,7 @@ import ( dssync "github.com/ipfs/go-datastore/sync" mh "github.com/multiformats/go-multihash" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) type allFeatures interface { @@ -221,3 +223,93 @@ func TestOfflineRecordsThenOnlineRepublish(t *testing.T) { t.Fatalf("keys are not equal expected %v, got %v", someHash, prov.keys[0]) } } + +func newMockKeyChanFunc(cids []cid.Cid) KeyChanFunc { + return func(ctx context.Context) (<-chan cid.Cid, error) { + outCh := make(chan cid.Cid) + + go func() { + defer close(outCh) + for _, c := range cids { + select { + case <-ctx.Done(): + return + case outCh <- c: + } + } + }() + + return outCh, nil + } +} + +func makeCIDs(n int) []cid.Cid { + cids := make([]cid.Cid, n) + for i := 0; i < n; i++ { + buf := make([]byte, 63) + _, err := rand.Read(buf) + if err != nil { + panic(err) + } + data, err := mh.Encode(buf, mh.SHA2_256) + if err != nil { + panic(err) + } + cids[i] = cid.NewCidV1(0, data) + } + + return cids +} + +func TestNewPrioritizedProvider(t *testing.T) { + cids := makeCIDs(6) + + testCases := []struct { + name string + priority []cid.Cid + all []cid.Cid + expected []cid.Cid + }{ + { + name: "basic test", + priority: cids[:3], + all: cids[3:], + expected: cids, + }, + { + name: "basic test inverted", + priority: cids[3:], + all: cids[:3], + expected: append(cids[3:], cids[:3]...), + }, + { + name: "no repeated", + priority: cids[3:], + all: cids[3:], + expected: cids[3:], + }, + { + name: "no repeated if duplicates in the prioritized channel", + priority: []cid.Cid{cids[0], cids[1], cids[0]}, + all: []cid.Cid{cids[2], cids[4], cids[5]}, + expected: []cid.Cid{cids[0], cids[1], cids[2], cids[4], cids[5]}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + stream := NewPrioritizedProvider(newMockKeyChanFunc(tc.priority), newMockKeyChanFunc(tc.all)) + ch, err := stream(ctx) + require.NoError(t, err) + + received := []cid.Cid{} + for c := range ch { + received = append(received, c) + } + require.Equal(t, tc.expected, received) + }) + } +} From 0b73f8a1d3ea58a83efc1843b3cdf2b1c1ed7d49 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 9 Apr 2024 11:48:17 +0200 Subject: [PATCH 11/12] docs: changelog for 0.19 --- CHANGELOG.md | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c9fa7bb7..e22af52c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,18 @@ The following emojis are used to highlight certain changes: ### Added +### Changed + +### Removed + +### Fixed + +### Security + +## [v0.19.0] + +### Added + * `routing/http/server` now adds `Cache-Control` HTTP header to GET requests: 15 seconds for empty responses, or 5 minutes for responses with providers. * `routing/http/server` the `/ipns` endpoint is more friendly to users opening URL in web browsers: returns `Content-Disposition` header and defaults to `application/vnd.ipfs.ipns-record` response when `Accept` is missing. * `provider`: @@ -26,15 +38,11 @@ The following emojis are used to highlight certain changes: * `go` version changed to 1.21 -### Removed - ### Fixed - 🛠️`routing/http/server`: delegated peer routing endpoint now supports both [PeerID string notaitons from libp2p specs](https://github.com/libp2p/specs/blob/master/peer-ids/peer-ids.md#string-representation). - `bitswap`: add missing client `WithBlockReceivedNotifier` and `WithoutDuplicatedBlockStats` options to the exchange. -### Security - ## [v0.18.0] ### Added From 76648b7e9f34d7c8ca8fa445bff28c5092a2c034 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Tue, 9 Apr 2024 11:49:06 +0200 Subject: [PATCH 12/12] chore: bump to v0.19.0 --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index 5775de3b2..0a972ecb1 100644 --- a/version.json +++ b/version.json @@ -1,3 +1,3 @@ { - "version": "v0.18.0" + "version": "v0.19.0" }