mirror of
https://github.com/ipfs/kubo.git
synced 2026-02-21 10:27:46 +08:00
Merge branch 'master' into merge-release-v0.39.0
resolve version.go conflict by keeping -dev version from master
This commit is contained in:
commit
823c11721d
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@ -29,7 +29,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
@ -38,12 +38,12 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: go
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
uses: github/codeql-action/autobuild@v4
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
uses: github/codeql-action/analyze@v4
|
||||
|
||||
4
.github/workflows/docker-check.yml
vendored
4
.github/workflows/docker-check.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: hadolint/hadolint-action@v3.3.0
|
||||
with:
|
||||
dockerfile: Dockerfile
|
||||
@ -41,7 +41,7 @@ jobs:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
4
.github/workflows/docker-image.yml
vendored
4
.github/workflows/docker-image.yml
vendored
@ -43,7 +43,7 @@ jobs:
|
||||
tags: ${{ steps.tags.outputs.value }}
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
@ -154,7 +154,7 @@ jobs:
|
||||
LEGACY_IMAGE_NAME: ipfs/go-ipfs
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
4
.github/workflows/gateway-conformance.yml
vendored
4
.github/workflows/gateway-conformance.yml
vendored
@ -47,7 +47,7 @@ jobs:
|
||||
|
||||
# 2. Build the kubo-gateway
|
||||
- name: Checkout kubo-gateway
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: kubo-gateway
|
||||
- name: Setup Go
|
||||
@ -133,7 +133,7 @@ jobs:
|
||||
|
||||
# 2. Build the kubo-gateway
|
||||
- name: Checkout kubo-gateway
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: kubo-gateway
|
||||
- name: Setup Go
|
||||
|
||||
2
.github/workflows/gobuild.yml
vendored
2
.github/workflows/gobuild.yml
vendored
@ -27,7 +27,7 @@ jobs:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
2
.github/workflows/golang-analysis.yml
vendored
2
.github/workflows/golang-analysis.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- uses: actions/setup-go@v6
|
||||
|
||||
2
.github/workflows/golint.yml
vendored
2
.github/workflows/golint.yml
vendored
@ -28,7 +28,7 @@ jobs:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
|
||||
2
.github/workflows/gotest.yml
vendored
2
.github/workflows/gotest.yml
vendored
@ -29,7 +29,7 @@ jobs:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Check out Kubo
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
|
||||
4
.github/workflows/interop.yml
vendored
4
.github/workflows/interop.yml
vendored
@ -32,7 +32,7 @@ jobs:
|
||||
run:
|
||||
shell: bash
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
@ -92,7 +92,7 @@ jobs:
|
||||
name: kubo
|
||||
path: cmd/ipfs
|
||||
- run: chmod +x cmd/ipfs/ipfs
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
repository: ipfs/ipfs-webui
|
||||
path: ipfs-webui
|
||||
|
||||
2
.github/workflows/sharness.yml
vendored
2
.github/workflows/sharness.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Checkout Kubo
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
path: kubo
|
||||
- name: Setup Go
|
||||
|
||||
2
.github/workflows/test-migrations.yml
vendored
2
.github/workflows/test-migrations.yml
vendored
@ -41,7 +41,7 @@ jobs:
|
||||
shell: bash
|
||||
steps:
|
||||
- name: Check out Kubo
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v6
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
# Kubo Changelogs
|
||||
|
||||
- [v0.40](docs/changelogs/v0.40.md)
|
||||
- [v0.39](docs/changelogs/v0.39.md)
|
||||
- [v0.38](docs/changelogs/v0.38.md)
|
||||
- [v0.37](docs/changelogs/v0.37.md)
|
||||
|
||||
@ -8,7 +8,7 @@ const (
|
||||
DefaultInlineDNSLink = false
|
||||
DefaultDeserializedResponses = true
|
||||
DefaultDisableHTMLErrors = false
|
||||
DefaultExposeRoutingAPI = false
|
||||
DefaultExposeRoutingAPI = true
|
||||
DefaultDiagnosticServiceURL = "https://check.ipfs.network"
|
||||
|
||||
// Gateway limit defaults from boxo
|
||||
|
||||
@ -2,6 +2,8 @@ package corehttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
@ -13,6 +15,9 @@ import (
|
||||
"github.com/ipfs/boxo/routing/http/types/iter"
|
||||
cid "github.com/ipfs/go-cid"
|
||||
core "github.com/ipfs/kubo/core"
|
||||
dht "github.com/libp2p/go-libp2p-kad-dht"
|
||||
"github.com/libp2p/go-libp2p-kad-dht/dual"
|
||||
"github.com/libp2p/go-libp2p-kad-dht/fullrt"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/routing"
|
||||
)
|
||||
@ -96,6 +101,60 @@ func (r *contentRouter) PutIPNS(ctx context.Context, name ipns.Name, record *ipn
|
||||
return r.n.Routing.PutValue(ctx, string(name.RoutingKey()), raw)
|
||||
}
|
||||
|
||||
func (r *contentRouter) GetClosestPeers(ctx context.Context, key cid.Cid) (iter.ResultIter[*types.PeerRecord], error) {
|
||||
// Per the spec, if the peer ID is empty, we should use self.
|
||||
if key == cid.Undef {
|
||||
return nil, errors.New("GetClosestPeers key is undefined")
|
||||
}
|
||||
|
||||
keyStr := string(key.Hash())
|
||||
var peers []peer.ID
|
||||
var err error
|
||||
|
||||
if r.n.DHTClient == nil {
|
||||
return nil, fmt.Errorf("GetClosestPeers not supported: DHT is not available")
|
||||
}
|
||||
|
||||
switch dhtClient := r.n.DHTClient.(type) {
|
||||
case *dual.DHT:
|
||||
// Only use WAN DHT for public HTTP Routing API.
|
||||
// LAN DHT contains private network peers that should not be exposed publicly.
|
||||
if dhtClient.WAN == nil {
|
||||
return nil, fmt.Errorf("GetClosestPeers not supported: WAN DHT is not available")
|
||||
}
|
||||
peers, err = dhtClient.WAN.GetClosestPeers(ctx, keyStr)
|
||||
case *fullrt.FullRT:
|
||||
peers, err = dhtClient.GetClosestPeers(ctx, keyStr)
|
||||
case *dht.IpfsDHT:
|
||||
peers, err = dhtClient.GetClosestPeers(ctx, keyStr)
|
||||
default:
|
||||
return nil, fmt.Errorf("GetClosestPeers not supported for DHT type %T", r.n.DHTClient)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// We have some DHT-closest peers. Find addresses for them.
|
||||
// The addresses should be in the peerstore.
|
||||
records := make([]*types.PeerRecord, 0, len(peers))
|
||||
for _, p := range peers {
|
||||
addrs := r.n.Peerstore.Addrs(p)
|
||||
rAddrs := make([]types.Multiaddr, len(addrs))
|
||||
for i, addr := range addrs {
|
||||
rAddrs[i] = types.Multiaddr{Multiaddr: addr}
|
||||
}
|
||||
record := types.PeerRecord{
|
||||
ID: &p,
|
||||
Schema: types.SchemaPeer,
|
||||
Addrs: rAddrs,
|
||||
}
|
||||
records = append(records, &record)
|
||||
}
|
||||
|
||||
return iter.ToResultIter(iter.FromSlice(records)), nil
|
||||
}
|
||||
|
||||
type peerChanIter struct {
|
||||
ch <-chan peer.AddrInfo
|
||||
cancel context.CancelFunc
|
||||
|
||||
27
docs/changelogs/v0.40.md
Normal file
27
docs/changelogs/v0.40.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Kubo changelog v0.40
|
||||
|
||||
<a href="https://ipshipyard.com/"><img align="right" src="https://github.com/user-attachments/assets/39ed3504-bb71-47f6-9bf8-cb9a1698f272" /></a>
|
||||
|
||||
This release was brought to you by the [Shipyard](https://ipshipyard.com/) team.
|
||||
|
||||
- [v0.40.0](#v0400)
|
||||
|
||||
## v0.40.0
|
||||
|
||||
- [Overview](#overview)
|
||||
- [🔦 Highlights](#-highlights)
|
||||
- [Routing V1 HTTP API now exposed by default](#routing-v1-http-api-now-exposed-by-default)
|
||||
- [📝 Changelog](#-changelog)
|
||||
- [👨👩👧👦 Contributors](#-contributors)
|
||||
|
||||
### Overview
|
||||
|
||||
### 🔦 Highlights
|
||||
|
||||
#### Routing V1 HTTP API now exposed by default
|
||||
|
||||
The [Routing V1 HTTP API](https://specs.ipfs.tech/routing/http-routing-v1/) is now exposed by default at `http://127.0.0.1:8080/routing/v1`. This allows light clients in browsers to use Kubo Gateway as a delegated routing backend instead of running a full DHT client. Support for [IPIP-476: Delegated Routing DHT Closest Peers API](https://github.com/ipfs/specs/pull/476) is included. Can be disabled via [`Gateway.ExposeRoutingAPI`](https://github.com/ipfs/kubo/blob/master/docs/config.md#gatewayexposeroutingapi).
|
||||
|
||||
### 📝 Changelog
|
||||
|
||||
### 👨👩👧👦 Contributors
|
||||
@ -1128,7 +1128,7 @@ Kubo will filter out routing results which are not actionable, for example, all
|
||||
graphsync providers will be skipped. If you need a generic pass-through, see
|
||||
standalone router implementation named [someguy](https://github.com/ipfs/someguy).
|
||||
|
||||
Default: `false`
|
||||
Default: `true`
|
||||
|
||||
Type: `flag`
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@ go 1.25
|
||||
replace github.com/ipfs/kubo => ./../../..
|
||||
|
||||
require (
|
||||
github.com/ipfs/boxo v0.35.2
|
||||
github.com/ipfs/boxo v0.35.3-0.20251118170232-e71f50ea2263
|
||||
github.com/ipfs/kubo v0.0.0-00010101000000-000000000000
|
||||
github.com/libp2p/go-libp2p v0.45.0
|
||||
github.com/multiformats/go-multiaddr v0.16.1
|
||||
|
||||
@ -291,8 +291,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
|
||||
github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
|
||||
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
||||
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
||||
github.com/ipfs/boxo v0.35.2 h1:0QZJJh6qrak28abENOi5OA8NjBnZM4p52SxeuIDqNf8=
|
||||
github.com/ipfs/boxo v0.35.2/go.mod h1:bZn02OFWwJtY8dDW9XLHaki59EC5o+TGDECXEbe1w8U=
|
||||
github.com/ipfs/boxo v0.35.3-0.20251118170232-e71f50ea2263 h1:7sSi4euS5Rb+RwQZOXrd/fURpC9kgbESD4DPykaLy0I=
|
||||
github.com/ipfs/boxo v0.35.3-0.20251118170232-e71f50ea2263/go.mod h1:bZn02OFWwJtY8dDW9XLHaki59EC5o+TGDECXEbe1w8U=
|
||||
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
|
||||
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
|
||||
github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
|
||||
|
||||
2
go.mod
2
go.mod
@ -22,7 +22,7 @@ require (
|
||||
github.com/hashicorp/go-version v1.7.0
|
||||
github.com/ipfs-shipyard/nopfs v0.0.14
|
||||
github.com/ipfs-shipyard/nopfs/ipfs v0.25.0
|
||||
github.com/ipfs/boxo v0.35.2
|
||||
github.com/ipfs/boxo v0.35.3-0.20251118170232-e71f50ea2263
|
||||
github.com/ipfs/go-block-format v0.2.3
|
||||
github.com/ipfs/go-cid v0.6.0
|
||||
github.com/ipfs/go-cidutil v0.1.0
|
||||
|
||||
4
go.sum
4
go.sum
@ -358,8 +358,8 @@ github.com/ipfs-shipyard/nopfs/ipfs v0.25.0 h1:OqNqsGZPX8zh3eFMO8Lf8EHRRnSGBMqcd
|
||||
github.com/ipfs-shipyard/nopfs/ipfs v0.25.0/go.mod h1:BxhUdtBgOXg1B+gAPEplkg/GpyTZY+kCMSfsJvvydqU=
|
||||
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
||||
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
||||
github.com/ipfs/boxo v0.35.2 h1:0QZJJh6qrak28abENOi5OA8NjBnZM4p52SxeuIDqNf8=
|
||||
github.com/ipfs/boxo v0.35.2/go.mod h1:bZn02OFWwJtY8dDW9XLHaki59EC5o+TGDECXEbe1w8U=
|
||||
github.com/ipfs/boxo v0.35.3-0.20251118170232-e71f50ea2263 h1:7sSi4euS5Rb+RwQZOXrd/fURpC9kgbESD4DPykaLy0I=
|
||||
github.com/ipfs/boxo v0.35.3-0.20251118170232-e71f50ea2263/go.mod h1:bZn02OFWwJtY8dDW9XLHaki59EC5o+TGDECXEbe1w8U=
|
||||
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
|
||||
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
|
||||
github.com/ipfs/go-block-format v0.0.3/go.mod h1:4LmD4ZUw0mhO+JSKdpWwrzATiEfM7WWgQ8H5l6P8MVk=
|
||||
|
||||
@ -42,7 +42,7 @@ type datastoreConfig struct {
|
||||
syncField bool
|
||||
}
|
||||
|
||||
// BadgerdsDatastoreConfig returns a configuration stub for a flatfs datastore
|
||||
// DatastoreConfigParser returns a configuration stub for a flatfs datastore
|
||||
// from the given parameters.
|
||||
func (*flatfsPlugin) DatastoreConfigParser() fsrepo.ConfigFromMap {
|
||||
return func(params map[string]interface{}) (fsrepo.DatastoreConfig, error) {
|
||||
|
||||
@ -2,9 +2,13 @@ package cli
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/ipfs/boxo/autoconf"
|
||||
"github.com/ipfs/boxo/ipns"
|
||||
"github.com/ipfs/boxo/routing/http/client"
|
||||
"github.com/ipfs/boxo/routing/http/types"
|
||||
@ -14,8 +18,14 @@ import (
|
||||
"github.com/ipfs/kubo/test/cli/harness"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
// swarmPeersOutput is used to parse the JSON output of 'ipfs swarm peers --enc=json'
|
||||
type swarmPeersOutput struct {
|
||||
Peers []struct{} `json:"Peers"`
|
||||
}
|
||||
|
||||
func TestRoutingV1Server(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@ -143,4 +153,132 @@ func TestRoutingV1Server(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, "/ipfs/"+cidStr, value.String())
|
||||
})
|
||||
|
||||
t.Run("GetClosestPeers returns error when DHT is disabled", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Test various routing types that don't support DHT
|
||||
routingTypes := []string{"none", "delegated", "custom"}
|
||||
for _, routingType := range routingTypes {
|
||||
t.Run("routing_type="+routingType, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Create node with specified routing type (DHT disabled)
|
||||
node := harness.NewT(t).NewNode().Init()
|
||||
node.UpdateConfig(func(cfg *config.Config) {
|
||||
cfg.Gateway.ExposeRoutingAPI = config.True
|
||||
cfg.Routing.Type = config.NewOptionalString(routingType)
|
||||
|
||||
// For custom routing type, we need to provide minimal valid config
|
||||
// otherwise daemon startup will fail
|
||||
if routingType == "custom" {
|
||||
// Configure a minimal HTTP router (no DHT)
|
||||
cfg.Routing.Routers = map[string]config.RouterParser{
|
||||
"http-only": {
|
||||
Router: config.Router{
|
||||
Type: config.RouterTypeHTTP,
|
||||
Parameters: config.HTTPRouterParams{
|
||||
Endpoint: "https://delegated-ipfs.dev",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
cfg.Routing.Methods = map[config.MethodName]config.Method{
|
||||
config.MethodNameProvide: {RouterName: "http-only"},
|
||||
config.MethodNameFindProviders: {RouterName: "http-only"},
|
||||
config.MethodNameFindPeers: {RouterName: "http-only"},
|
||||
config.MethodNameGetIPNS: {RouterName: "http-only"},
|
||||
config.MethodNamePutIPNS: {RouterName: "http-only"},
|
||||
}
|
||||
}
|
||||
|
||||
// For delegated routing type, ensure we have at least one HTTP router
|
||||
// to avoid daemon startup failure
|
||||
if routingType == "delegated" {
|
||||
// Use a minimal delegated router configuration
|
||||
cfg.Routing.DelegatedRouters = []string{"https://delegated-ipfs.dev"}
|
||||
// Delegated routing doesn't support providing, must be disabled
|
||||
cfg.Provide.Enabled = config.False
|
||||
}
|
||||
})
|
||||
node.StartDaemon()
|
||||
|
||||
c, err := client.New(node.GatewayURL())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to get closest peers - should fail gracefully with an error
|
||||
testCid, err := cid.Decode("QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn")
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = c.GetClosestPeers(context.Background(), testCid)
|
||||
require.Error(t, err)
|
||||
// All these routing types should indicate DHT is not available
|
||||
// The exact error message may vary based on implementation details
|
||||
errStr := err.Error()
|
||||
assert.True(t,
|
||||
strings.Contains(errStr, "not supported") ||
|
||||
strings.Contains(errStr, "not available") ||
|
||||
strings.Contains(errStr, "500"),
|
||||
"Expected error indicating DHT not available for routing type %s, got: %s", routingType, errStr)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("GetClosestPeers returns peers for self", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
routingTypes := []string{"auto", "autoclient", "dht", "dhtclient"}
|
||||
for _, routingType := range routingTypes {
|
||||
t.Run("routing_type="+routingType, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Single node with DHT and real bootstrap peers
|
||||
node := harness.NewT(t).NewNode().Init()
|
||||
node.UpdateConfig(func(cfg *config.Config) {
|
||||
cfg.Gateway.ExposeRoutingAPI = config.True
|
||||
cfg.Routing.Type = config.NewOptionalString(routingType)
|
||||
// Set real bootstrap peers from boxo/autoconf
|
||||
cfg.Bootstrap = autoconf.FallbackBootstrapPeers
|
||||
})
|
||||
node.StartDaemon()
|
||||
|
||||
// Wait for node to connect to bootstrap peers and populate WAN DHT routing table
|
||||
minPeers := len(autoconf.FallbackBootstrapPeers)
|
||||
require.EventuallyWithT(t, func(t *assert.CollectT) {
|
||||
res := node.RunIPFS("swarm", "peers", "--enc=json")
|
||||
var output swarmPeersOutput
|
||||
err := json.Unmarshal(res.Stdout.Bytes(), &output)
|
||||
assert.NoError(t, err)
|
||||
peerCount := len(output.Peers)
|
||||
// Wait until we have at least minPeers connected
|
||||
assert.GreaterOrEqual(t, peerCount, minPeers,
|
||||
"waiting for at least %d bootstrap peers, currently have %d", minPeers, peerCount)
|
||||
}, 30*time.Second, time.Second)
|
||||
|
||||
c, err := client.New(node.GatewayURL())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Query for closest peers to our own peer ID
|
||||
key := peer.ToCid(node.PeerID())
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
||||
defer cancel()
|
||||
resultsIter, err := c.GetClosestPeers(ctx, key)
|
||||
require.NoError(t, err)
|
||||
|
||||
records, err := iter.ReadAllResults(resultsIter)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify we got some peers back from WAN DHT
|
||||
assert.NotEmpty(t, records, "should return some peers close to own peerid")
|
||||
|
||||
// Verify structure of returned records
|
||||
for _, record := range records {
|
||||
assert.Equal(t, types.SchemaPeer, record.Schema)
|
||||
assert.NotNil(t, record.ID)
|
||||
assert.NotEmpty(t, record.Addrs, "peer record should have addresses")
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -19,13 +19,14 @@ import (
|
||||
// (https://specs.ipfs.tech/routing/http-routing-v1/) server implementation
|
||||
// based on github.com/ipfs/boxo/routing/http/server
|
||||
type MockHTTPContentRouter struct {
|
||||
m sync.Mutex
|
||||
provideBitswapCalls int
|
||||
findProvidersCalls int
|
||||
findPeersCalls int
|
||||
providers map[cid.Cid][]types.Record
|
||||
peers map[peer.ID][]*types.PeerRecord
|
||||
Debug bool
|
||||
m sync.Mutex
|
||||
provideBitswapCalls int
|
||||
findProvidersCalls int
|
||||
findPeersCalls int
|
||||
getClosestPeersCalls int
|
||||
providers map[cid.Cid][]types.Record
|
||||
peers map[peer.ID][]*types.PeerRecord
|
||||
Debug bool
|
||||
}
|
||||
|
||||
func (r *MockHTTPContentRouter) FindProviders(ctx context.Context, key cid.Cid, limit int) (iter.ResultIter[types.Record], error) {
|
||||
@ -115,3 +116,30 @@ func (r *MockHTTPContentRouter) AddProvider(key cid.Cid, record types.Record) {
|
||||
r.peers[*pid] = append(r.peers[*pid], peerRecord)
|
||||
}
|
||||
}
|
||||
|
||||
func (r *MockHTTPContentRouter) GetClosestPeers(ctx context.Context, key cid.Cid) (iter.ResultIter[*types.PeerRecord], error) {
|
||||
r.m.Lock()
|
||||
defer r.m.Unlock()
|
||||
r.getClosestPeersCalls++
|
||||
|
||||
if r.peers == nil {
|
||||
r.peers = make(map[peer.ID][]*types.PeerRecord)
|
||||
}
|
||||
pid, err := peer.FromCid(key)
|
||||
if err != nil {
|
||||
return iter.FromSlice([]iter.Result[*types.PeerRecord]{}), nil
|
||||
}
|
||||
records, found := r.peers[pid]
|
||||
if !found {
|
||||
return iter.FromSlice([]iter.Result[*types.PeerRecord]{}), nil
|
||||
}
|
||||
|
||||
results := make([]iter.Result[*types.PeerRecord], len(records))
|
||||
for i, rec := range records {
|
||||
results[i] = iter.Result[*types.PeerRecord]{Val: rec}
|
||||
if r.Debug {
|
||||
fmt.Printf("MockHTTPContentRouter.GetPeers(%s) result: %+v\n", pid.String(), rec)
|
||||
}
|
||||
}
|
||||
return iter.FromSlice(results), nil
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ require (
|
||||
github.com/huin/goupnp v1.3.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/ipfs/bbloom v0.0.4 // indirect
|
||||
github.com/ipfs/boxo v0.35.2 // indirect
|
||||
github.com/ipfs/boxo v0.35.3-0.20251118170232-e71f50ea2263 // indirect
|
||||
github.com/ipfs/go-bitfield v1.1.0 // indirect
|
||||
github.com/ipfs/go-block-format v0.2.3 // indirect
|
||||
github.com/ipfs/go-cid v0.6.0 // indirect
|
||||
|
||||
@ -334,8 +334,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/ipfs/bbloom v0.0.4 h1:Gi+8EGJ2y5qiD5FbsbpX/TMNcJw8gSqr7eyjHa4Fhvs=
|
||||
github.com/ipfs/bbloom v0.0.4/go.mod h1:cS9YprKXpoZ9lT0n/Mw/a6/aFV6DTjTLYHeA+gyqMG0=
|
||||
github.com/ipfs/boxo v0.35.2 h1:0QZJJh6qrak28abENOi5OA8NjBnZM4p52SxeuIDqNf8=
|
||||
github.com/ipfs/boxo v0.35.2/go.mod h1:bZn02OFWwJtY8dDW9XLHaki59EC5o+TGDECXEbe1w8U=
|
||||
github.com/ipfs/boxo v0.35.3-0.20251118170232-e71f50ea2263 h1:7sSi4euS5Rb+RwQZOXrd/fURpC9kgbESD4DPykaLy0I=
|
||||
github.com/ipfs/boxo v0.35.3-0.20251118170232-e71f50ea2263/go.mod h1:bZn02OFWwJtY8dDW9XLHaki59EC5o+TGDECXEbe1w8U=
|
||||
github.com/ipfs/go-bitfield v1.1.0 h1:fh7FIo8bSwaJEh6DdTWbCeZ1eqOaOkKFI74SCnsWbGA=
|
||||
github.com/ipfs/go-bitfield v1.1.0/go.mod h1:paqf1wjq/D2BBmzfTVFlJQ9IlFOZpg422HL0HqsGWHU=
|
||||
github.com/ipfs/go-block-format v0.2.3 h1:mpCuDaNXJ4wrBJLrtEaGFGXkferrw5eqVvzaHhtFKQk=
|
||||
|
||||
@ -11,7 +11,7 @@ import (
|
||||
var CurrentCommit string
|
||||
|
||||
// CurrentVersionNumber is the current application's version literal.
|
||||
const CurrentVersionNumber = "0.39.0"
|
||||
const CurrentVersionNumber = "0.40.0-dev"
|
||||
|
||||
const ApiVersion = "/kubo/" + CurrentVersionNumber + "/" //nolint
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user