@cryptotaxi247 / kubo / commits / d1b9e41fc

feat: Delegated routing with custom configuration. (#9274)

New multi-router configuration system based on https://hackmd.io/G1KRDEX5T3qyfoBMkIrBew#Methods - Added a new routing type: "custom" - Added specific struct types for different Routers (instead of map[string]interface{}) - Added `Duration` config type, to make easier time string parsing - Added config documentation. - Use the latest go-delegated-routing library version with GET support. - Added changelog notes for this feature. It: - closes #9157 - closes #9079 - closes #9186

Antonio Navarro Perez committed Sep 22, 2022 at 15:47 UTC d1b9e41fc25cba30c2349d0b16bf857c00e9331f
31 files changed +1841 -418
CHANGELOG.md
+1
@@ -1,5 +1,6 @@
1 # Kubo Changelogs
2
3 +- [v0.16](docs/changelogs/v0.16.md)
4 - [v0.15](docs/changelogs/v0.15.md)
5 - [v0.14](docs/changelogs/v0.14.md)
6 - [v0.13](docs/changelogs/v0.13.md)
cmd/ipfs/daemon.go
+13 -1
@@ -59,6 +59,7 @@ const (
59 routingOptionDHTKwd = "dht"
60 routingOptionDHTServerKwd = "dhtserver"
61 routingOptionNoneKwd = "none"
62 + routingOptionCustomKwd = "custom"
63 routingOptionDefaultKwd = "default"
64 unencryptTransportKwd = "disable-transport-encryption"
65 unrestrictedApiAccessKwd = "unrestricted-api"
@@ -401,7 +402,10 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
402
403 routingOption, _ := req.Options[routingOptionKwd].(string)
404 if routingOption == routingOptionDefaultKwd {
404 - routingOption = cfg.Routing.Type.WithDefault(routingOptionDHTKwd)
405 + routingOption = cfg.Routing.Type
406 + if routingOption == "" {
407 + routingOption = routingOptionDHTKwd
408 + }
409 }
410 switch routingOption {
411 case routingOptionSupernodeKwd:
@@ -414,6 +418,14 @@ func daemonFunc(req *cmds.Request, re cmds.ResponseEmitter, env cmds.Environment
418 ncfg.Routing = libp2p.DHTServerOption
419 case routingOptionNoneKwd:
420 ncfg.Routing = libp2p.NilRouterOption
421 + case routingOptionCustomKwd:
422 + ncfg.Routing = libp2p.ConstructDelegatedRouting(
423 + cfg.Routing.Routers,
424 + cfg.Routing.Methods,
425 + cfg.Identity.PeerID,
426 + cfg.Addresses.Swarm,
427 + cfg.Identity.PrivKey,
428 + )
429 default:
430 return fmt.Errorf("unrecognized routing option: %s", routingOption)
431 }
config/init.go
+9 -1
@@ -48,7 +48,15 @@ func InitWithIdentity(identity Identity) (*Config, error) {
48 },
49
50 Routing: Routing{
51 - Type: NewOptionalString("dht"),
51 + Type: "dht",
52 + Methods: Methods{
53 + MethodNameFindPeers: Method{},
54 + MethodNameFindProviders: Method{},
55 + MethodNameGetIPNS: Method{},
56 + MethodNameProvide: Method{},
57 + MethodNamePutIPNS: Method{},
58 + },
59 + Routers: nil,
60 },
61
62 // setup the node mount points.
config/profile.go
+1 -1
@@ -174,7 +174,7 @@ functionality - performance of content discovery and data
174 fetching may be degraded.
175 `,
176 Transform: func(c *Config) error {
177 - c.Routing.Type = NewOptionalString("dhtclient")
177 + c.Routing.Type = "dhtclient"
178 c.AutoNAT.ServiceMode = AutoNATServiceDisabled
179 c.Reprovider.Interval = "0"
180
config/routing.go
+128 -14
@@ -1,28 +1,101 @@
1 package config
2
3 +import (
4 + "encoding/json"
5 + "fmt"
6 +)
7 +
8 // Routing defines configuration options for libp2p routing
9 type Routing struct {
10 // Type sets default daemon routing mode.
11 //
7 - // Can be one of "dht", "dhtclient", "dhtserver", "none", or unset.
8 - Type *OptionalString `json:",omitempty"`
12 + // Can be one of "dht", "dhtclient", "dhtserver", "none", or "custom".
13 + // When "custom" is set, you can specify a list of Routers.
14 + Type string
15
10 - Routers map[string]Router
16 + Routers Routers
17 +
18 + Methods Methods
19 }
20
21 type Router struct {
22
15 - // Currenly only supported Type is "reframe".
23 + // Currenly supported Types are "reframe", "dht", "parallel", "sequential".
24 // Reframe type allows to add other resolvers using the Reframe spec:
25 // https://github.com/ipfs/specs/tree/main/reframe
26 // In the future we will support "dht" and other Types here.
19 - Type string
20 -
21 - Enabled Flag `json:",omitempty"`
27 + Type RouterType
28
29 // Parameters are extra configuration that this router might need.
30 // A common one for reframe router is "Endpoint".
25 - Parameters map[string]string
31 + Parameters interface{}
32 +}
33 +
34 +type Routers map[string]RouterParser
35 +type Methods map[MethodName]Method
36 +
37 +func (m Methods) Check() error {
38 +
39 + // Check supported methods
40 + for _, mn := range MethodNameList {
41 + _, ok := m[mn]
42 + if !ok {
43 + return fmt.Errorf("method name %q is missing from Routing.Methods config param", mn)
44 + }
45 + }
46 +
47 + // Check unsupported methods
48 + for k := range m {
49 + seen := false
50 + for _, mn := range MethodNameList {
51 + if mn == k {
52 + seen = true
53 + break
54 + }
55 + }
56 +
57 + if seen {
58 + continue
59 + }
60 +
61 + return fmt.Errorf("method name %q is not a supported method on Routing.Methods config param", k)
62 + }
63 +
64 + return nil
65 +}
66 +
67 +type RouterParser struct {
68 + Router
69 +}
70 +
71 +func (r *RouterParser) UnmarshalJSON(b []byte) error {
72 + out := Router{}
73 + out.Parameters = &json.RawMessage{}
74 + if err := json.Unmarshal(b, &out); err != nil {
75 + return err
76 + }
77 + raw := out.Parameters.(*json.RawMessage)
78 +
79 + var p interface{}
80 + switch out.Type {
81 + case RouterTypeReframe:
82 + p = &ReframeRouterParams{}
83 + case RouterTypeDHT:
84 + p = &DHTRouterParams{}
85 + case RouterTypeSequential:
86 + p = &ComposableRouterParams{}
87 + case RouterTypeParallel:
88 + p = &ComposableRouterParams{}
89 + }
90 +
91 + if err := json.Unmarshal(*raw, &p); err != nil {
92 + return err
93 + }
94 +
95 + r.Router.Type = out.Type
96 + r.Router.Parameters = p
97 +
98 + return nil
99 }
100
101 // Type is the routing type.
@@ -30,15 +103,56 @@ type Router struct {
103 type RouterType string
104
105 const (
33 - RouterTypeReframe RouterType = "reframe"
106 + RouterTypeReframe RouterType = "reframe"
107 + RouterTypeDHT RouterType = "dht"
108 + RouterTypeSequential RouterType = "sequential"
109 + RouterTypeParallel RouterType = "parallel"
110 )
111
36 -type RouterParam string
112 +type DHTMode string
113
114 const (
39 - // RouterParamEndpoint is the URL where the routing implementation will point to get the information.
40 - // Usually used for reframe Routers.
41 - RouterParamEndpoint RouterParam = "Endpoint"
115 + DHTModeServer DHTMode = "server"
116 + DHTModeClient DHTMode = "client"
117 + DHTModeAuto DHTMode = "auto"
118 +)
119
43 - RouterParamPriority RouterParam = "Priority"
120 +type MethodName string
121 +
122 +const (
123 + MethodNameProvide MethodName = "provide"
124 + MethodNameFindProviders MethodName = "find-providers"
125 + MethodNameFindPeers MethodName = "find-peers"
126 + MethodNameGetIPNS MethodName = "get-ipns"
127 + MethodNamePutIPNS MethodName = "put-ipns"
128 )
129 +
130 +var MethodNameList = []MethodName{MethodNameProvide, MethodNameFindPeers, MethodNameFindProviders, MethodNameGetIPNS, MethodNamePutIPNS}
131 +
132 +type ReframeRouterParams struct {
133 + // Endpoint is the URL where the routing implementation will point to get the information.
134 + // Usually used for reframe Routers.
135 + Endpoint string
136 +}
137 +
138 +type DHTRouterParams struct {
139 + Mode DHTMode
140 + AcceleratedDHTClient bool `json:",omitempty"`
141 + PublicIPNetwork bool
142 +}
143 +
144 +type ComposableRouterParams struct {
145 + Routers []ConfigRouter
146 + Timeout *OptionalDuration `json:",omitempty"`
147 +}
148 +
149 +type ConfigRouter struct {
150 + RouterName string
151 + Timeout Duration
152 + IgnoreErrors bool
153 + ExecuteAfter *OptionalDuration `json:",omitempty"`
154 +}
155 +
156 +type Method struct {
157 + RouterName string
158 +}
config/routing_test.go new
+195
@@ -0,0 +1,195 @@
1 +package config
2 +
3 +import (
4 + "encoding/json"
5 + "testing"
6 + "time"
7 +
8 + "github.com/stretchr/testify/require"
9 +)
10 +
11 +func TestRouterParameters(t *testing.T) {
12 + require := require.New(t)
13 + sec := time.Second
14 + min := time.Minute
15 + r := Routing{
16 + Type: "custom",
17 + Routers: map[string]RouterParser{
18 + "router-dht": {Router{
19 + Type: RouterTypeDHT,
20 + Parameters: DHTRouterParams{
21 + Mode: "auto",
22 + AcceleratedDHTClient: true,
23 + PublicIPNetwork: false,
24 + },
25 + }},
26 + "router-reframe": {Router{
27 + Type: RouterTypeReframe,
28 + Parameters: ReframeRouterParams{
29 + Endpoint: "reframe-endpoint",
30 + },
31 + }},
32 + "router-parallel": {Router{
33 + Type: RouterTypeParallel,
34 + Parameters: ComposableRouterParams{
35 + Routers: []ConfigRouter{
36 + {
37 + RouterName: "router-dht",
38 + Timeout: Duration{10 * time.Second},
39 + IgnoreErrors: true,
40 + },
41 + {
42 + RouterName: "router-reframe",
43 + Timeout: Duration{10 * time.Second},
44 + IgnoreErrors: false,
45 + ExecuteAfter: &OptionalDuration{&sec},
46 + },
47 + },
48 + Timeout: &OptionalDuration{&min},
49 + }},
50 + },
51 + "router-sequential": {Router{
52 + Type: RouterTypeSequential,
53 + Parameters: ComposableRouterParams{
54 + Routers: []ConfigRouter{
55 + {
56 + RouterName: "router-dht",
57 + Timeout: Duration{10 * time.Second},
58 + IgnoreErrors: true,
59 + },
60 + {
61 + RouterName: "router-reframe",
62 + Timeout: Duration{10 * time.Second},
63 + IgnoreErrors: false,
64 + },
65 + },
66 + Timeout: &OptionalDuration{&min},
67 + }},
68 + },
69 + },
70 + Methods: Methods{
71 + MethodNameFindPeers: {
72 + RouterName: "router-reframe",
73 + },
74 + MethodNameFindProviders: {
75 + RouterName: "router-dht",
76 + },
77 + MethodNameGetIPNS: {
78 + RouterName: "router-sequential",
79 + },
80 + MethodNameProvide: {
81 + RouterName: "router-parallel",
82 + },
83 + MethodNamePutIPNS: {
84 + RouterName: "router-parallel",
85 + },
86 + },
87 + }
88 +
89 + out, err := json.Marshal(r)
90 + require.NoError(err)
91 +
92 + r2 := &Routing{}
93 +
94 + err = json.Unmarshal(out, r2)
95 + require.NoError(err)
96 +
97 + require.Equal(5, len(r2.Methods))
98 +
99 + dhtp := r2.Routers["router-dht"].Parameters
100 + require.IsType(&DHTRouterParams{}, dhtp)
101 +
102 + rp := r2.Routers["router-reframe"].Parameters
103 + require.IsType(&ReframeRouterParams{}, rp)
104 +
105 + sp := r2.Routers["router-sequential"].Parameters
106 + require.IsType(&ComposableRouterParams{}, sp)
107 +
108 + pp := r2.Routers["router-parallel"].Parameters
109 + require.IsType(&ComposableRouterParams{}, pp)
110 +}
111 +
112 +func TestRouterMissingParameters(t *testing.T) {
113 + require := require.New(t)
114 +
115 + r := Routing{
116 + Type: "custom",
117 + Routers: map[string]RouterParser{
118 + "router-wrong-reframe": {Router{
119 + Type: RouterTypeReframe,
120 + Parameters: DHTRouterParams{
121 + Mode: "auto",
122 + AcceleratedDHTClient: true,
123 + PublicIPNetwork: false,
124 + },
125 + }},
126 + },
127 + Methods: Methods{
128 + MethodNameFindPeers: {
129 + RouterName: "router-wrong-reframe",
130 + },
131 + MethodNameFindProviders: {
132 + RouterName: "router-wrong-reframe",
133 + },
134 + MethodNameGetIPNS: {
135 + RouterName: "router-wrong-reframe",
136 + },
137 + MethodNameProvide: {
138 + RouterName: "router-wrong-reframe",
139 + },
140 + MethodNamePutIPNS: {
141 + RouterName: "router-wrong-reframe",
142 + },
143 + },
144 + }
145 +
146 + out, err := json.Marshal(r)
147 + require.NoError(err)
148 +
149 + r2 := &Routing{}
150 +
151 + err = json.Unmarshal(out, r2)
152 + require.NoError(err)
153 + require.Empty(r2.Routers["router-wrong-reframe"].Parameters.(*ReframeRouterParams).Endpoint)
154 +}
155 +
156 +func TestMethods(t *testing.T) {
157 + require := require.New(t)
158 +
159 + methodsOK := Methods{
160 + MethodNameFindPeers: {
161 + RouterName: "router-wrong-reframe",
162 + },
163 + MethodNameFindProviders: {
164 + RouterName: "router-wrong-reframe",
165 + },
166 + MethodNameGetIPNS: {
167 + RouterName: "router-wrong-reframe",
168 + },
169 + MethodNameProvide: {
170 + RouterName: "router-wrong-reframe",
171 + },
172 + MethodNamePutIPNS: {
173 + RouterName: "router-wrong-reframe",
174 + },
175 + }
176 +
177 + require.NoError(methodsOK.Check())
178 +
179 + methodsMissing := Methods{
180 + MethodNameFindPeers: {
181 + RouterName: "router-wrong-reframe",
182 + },
183 + MethodNameGetIPNS: {
184 + RouterName: "router-wrong-reframe",
185 + },
186 + MethodNameProvide: {
187 + RouterName: "router-wrong-reframe",
188 + },
189 + MethodNamePutIPNS: {
190 + RouterName: "router-wrong-reframe",
191 + },
192 + }
193 +
194 + require.Error(methodsMissing.Check())
195 +}
config/types.go
+32
@@ -262,6 +262,38 @@ func (d OptionalDuration) String() string {
262 var _ json.Unmarshaler = (*OptionalDuration)(nil)
263 var _ json.Marshaler = (*OptionalDuration)(nil)
264
265 +type Duration struct {
266 + time.Duration
267 +}
268 +
269 +func (d Duration) MarshalJSON() ([]byte, error) {
270 + return json.Marshal(d.String())
271 +}
272 +
273 +func (d *Duration) UnmarshalJSON(b []byte) error {
274 + var v interface{}
275 + if err := json.Unmarshal(b, &v); err != nil {
276 + return err
277 + }
278 + switch value := v.(type) {
279 + case float64:
280 + d.Duration = time.Duration(value)
281 + return nil
282 + case string:
283 + var err error
284 + d.Duration, err = time.ParseDuration(value)
285 + if err != nil {
286 + return err
287 + }
288 + return nil
289 + default:
290 + return fmt.Errorf("unable to parse duration, expected a duration string or a float, but got %T", v)
291 + }
292 +}
293 +
294 +var _ json.Unmarshaler = (*Duration)(nil)
295 +var _ json.Marshaler = (*Duration)(nil)
296 +
297 // OptionalInteger represents an integer that has a default value
298 //
299 // When encoded in json, Default is encoded as "null"
core/core.go
+12 -12
@@ -87,18 +87,18 @@ type IpfsNode struct {
87 RecordValidator record.Validator
88
89 // Online
90 - PeerHost p2phost.Host `optional:"true"` // the network host (server+client)
91 - Peering *peering.PeeringService `optional:"true"`
92 - Filters *ma.Filters `optional:"true"`
93 - Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper
94 - Routing irouting.TieredRouter `optional:"true"` // the routing system. recommend ipfs-dht
95 - DNSResolver *madns.Resolver // the DNS resolver
96 - Exchange exchange.Interface // the block exchange + strategy (bitswap)
97 - Namesys namesys.NameSystem // the name system, resolves paths to hashes
98 - Provider provider.System // the value provider system
99 - IpnsRepub *ipnsrp.Republisher `optional:"true"`
100 - GraphExchange graphsync.GraphExchange `optional:"true"`
101 - ResourceManager network.ResourceManager `optional:"true"`
90 + PeerHost p2phost.Host `optional:"true"` // the network host (server+client)
91 + Peering *peering.PeeringService `optional:"true"`
92 + Filters *ma.Filters `optional:"true"`
93 + Bootstrapper io.Closer `optional:"true"` // the periodic bootstrapper
94 + Routing irouting.ProvideManyRouter `optional:"true"` // the routing system. recommend ipfs-dht
95 + DNSResolver *madns.Resolver // the DNS resolver
96 + Exchange exchange.Interface // the block exchange + strategy (bitswap)
97 + Namesys namesys.NameSystem // the name system, resolves paths to hashes
98 + Provider provider.System // the value provider system
99 + IpnsRepub *ipnsrp.Republisher `optional:"true"`
100 + GraphExchange graphsync.GraphExchange `optional:"true"`
101 + ResourceManager network.ResourceManager `optional:"true"`
102
103 PubSub *pubsub.PubSub `optional:"true"`
104 PSRouter *psrouter.PubsubValueStore `optional:"true"`
core/core_test.go
+67 -17
@@ -117,8 +117,6 @@ func TestDelegatedRoutingSingle(t *testing.T) {
117 err = n.Routing.PutValue(ctx, theID, v)
118 require.NoError(err)
119
120 - err = n.Routing.PutValue(ctx, theErrorID, v)
121 - require.Error(err)
120 }
121
122 func TestDelegatedRoutingMulti(t *testing.T) {
@@ -164,12 +162,6 @@ func TestDelegatedRoutingMulti(t *testing.T) {
162 require.NoError(err)
163 require.NotNil(v)
164 require.Contains(string(v), "RECORD FROM SERVICE 2")
167 -
168 - err = n.Routing.PutValue(ctx, theID1, v)
169 - require.Error(err)
170 -
171 - err = n.Routing.PutValue(ctx, theID2, v)
172 - require.Error(err)
165 }
166
167 func StartRoutingServer(t *testing.T, d drs.DelegatedRoutingService) string {
@@ -187,16 +179,41 @@ func StartRoutingServer(t *testing.T, d drs.DelegatedRoutingService) string {
179 func GetNode(t *testing.T, reframeURLs ...string) *IpfsNode {
180 t.Helper()
181
190 - routers := make(map[string]config.Router)
182 + routers := make(config.Routers)
183 + var routerNames []string
184 for i, ru := range reframeURLs {
192 - routers[fmt.Sprintf("reframe-%d", i)] = config.Router{
193 - Type: string(config.RouterTypeReframe),
194 - Parameters: map[string]string{
195 - string(config.RouterParamEndpoint): ru,
196 - },
197 - }
185 + rn := fmt.Sprintf("reframe-%d", i)
186 + routerNames = append(routerNames, rn)
187 + routers[rn] =
188 + config.RouterParser{
189 + Router: config.Router{
190 + Type: config.RouterTypeReframe,
191 + Parameters: &config.ReframeRouterParams{
192 + Endpoint: ru,
193 + },
194 + },
195 + }
196 + }
197 +
198 + var crs []config.ConfigRouter
199 + for _, rn := range routerNames {
200 + crs = append(crs, config.ConfigRouter{
201 + RouterName: rn,
202 + IgnoreErrors: true,
203 + Timeout: config.Duration{Duration: time.Minute},
204 + })
205 }
206
207 + const parallelRouterName = "parallel-router"
208 +
209 + routers[parallelRouterName] = config.RouterParser{
210 + Router: config.Router{
211 + Type: config.RouterTypeParallel,
212 + Parameters: &config.ComposableRouterParams{
213 + Routers: crs,
214 + },
215 + },
216 + }
217 cfg := config.Config{
218 Identity: testIdentity,
219 Addresses: config.Addresses{
@@ -204,8 +221,25 @@ func GetNode(t *testing.T, reframeURLs ...string) *IpfsNode {
221 API: []string{"/ip4/127.0.0.1/tcp/0"},
222 },
223 Routing: config.Routing{
207 - Type: config.NewOptionalString("none"),
224 + Type: "custom",
225 Routers: routers,
226 + Methods: config.Methods{
227 + config.MethodNameFindPeers: config.Method{
228 + RouterName: parallelRouterName,
229 + },
230 + config.MethodNameFindProviders: config.Method{
231 + RouterName: parallelRouterName,
232 + },
233 + config.MethodNameGetIPNS: config.Method{
234 + RouterName: parallelRouterName,
235 + },
236 + config.MethodNameProvide: config.Method{
237 + RouterName: parallelRouterName,
238 + },
239 + config.MethodNamePutIPNS: config.Method{
240 + RouterName: parallelRouterName,
241 + },
242 + },
243 },
244 }
245
@@ -214,7 +248,19 @@ func GetNode(t *testing.T, reframeURLs ...string) *IpfsNode {
248 D: syncds.MutexWrap(datastore.NewMapDatastore()),
249 }
250
217 - n, err := NewNode(context.Background(), &BuildCfg{Repo: r, Online: true, Routing: libp2p.NilRouterOption})
251 + n, err := NewNode(context.Background(),
252 + &BuildCfg{
253 + Repo: r,
254 + Online: true,
255 + Routing: libp2p.ConstructDelegatedRouting(
256 + cfg.Routing.Routers,
257 + cfg.Routing.Methods,
258 + cfg.Identity.PeerID,
259 + cfg.Addresses.Swarm,
260 + cfg.Identity.PrivKey,
261 + ),
262 + },
263 + )
264 require.NoError(t, err)
265
266 return n
@@ -240,6 +286,10 @@ func (drs *delegatedRoutingService) FindProviders(ctx context.Context, key cid.C
286 return nil, errNotSupported
287 }
288
289 +func (drs *delegatedRoutingService) Provide(ctx context.Context, req *client.ProvideRequest) (<-chan client.ProvideAsyncResult, error) {
290 + return nil, errNotSupported
291 +}
292 +
293 func (drs *delegatedRoutingService) GetIPNS(ctx context.Context, id []byte) (<-chan client.GetIPNSAsyncResult, error) {
294 ctx, cancel := context.WithCancel(ctx)
295 ch := make(chan client.GetIPNSAsyncResult)
core/node/bitswap.go
+1 -1
@@ -55,7 +55,7 @@ type onlineExchangeIn struct {
55
56 Mctx helpers.MetricsCtx
57 Host host.Host
58 - Rt irouting.TieredRouter
58 + Rt irouting.ProvideManyRouter
59 Bs blockstore.GCBlockstore
60 BitswapOpts []bitswap.Option `group:"bitswap-options"`
61 }
core/node/groups.go
-1
@@ -165,7 +165,6 @@ func LibP2P(bcfg *BuildCfg, cfg *config.Config) fx.Option {
165 fx.Provide(libp2p.ContentRouting),
166
167 fx.Provide(libp2p.BaseRouting(cfg.Experimental.AcceleratedDHTClient)),
168 - fx.Provide(libp2p.DelegatedRouting(cfg.Routing.Routers)),
168 maybeProvide(libp2p.PubsubRouter, bcfg.getOpt("ipnsps")),
169
170 maybeProvide(libp2p.BandwidthCounter, !cfg.Swarm.DisableBandwidthMetrics),
core/node/ipns.go
+3 -4
@@ -11,11 +11,10 @@ import (
11 "github.com/libp2p/go-libp2p/core/peerstore"
12 madns "github.com/multiformats/go-multiaddr-dns"
13
14 - irouting "github.com/ipfs/kubo/routing"
15 -
14 "github.com/ipfs/go-namesys"
15 "github.com/ipfs/go-namesys/republisher"
16 "github.com/ipfs/kubo/repo"
17 + irouting "github.com/ipfs/kubo/routing"
18 )
19
20 const DefaultIpnsCacheSize = 128
@@ -29,8 +28,8 @@ func RecordValidator(ps peerstore.Peerstore) record.Validator {
28 }
29
30 // Namesys creates new name system
32 -func Namesys(cacheSize int) func(rt irouting.TieredRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) {
33 - return func(rt irouting.TieredRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) {
31 +func Namesys(cacheSize int) func(rt irouting.ProvideManyRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) {
32 + return func(rt irouting.ProvideManyRouter, rslv *madns.Resolver, repo repo.Repo) (namesys.NameSystem, error) {
33 opts := []namesys.Option{
34 namesys.WithDatastore(repo.Datastore()),
35 namesys.WithDNSResolver(rslv),
core/node/libp2p/routing.go
+9 -43
@@ -129,39 +129,6 @@ func BaseRouting(experimentalDHTClient bool) interface{} {
129 }
130 }
131
132 -type delegatedRouterOut struct {
133 - fx.Out
134 -
135 - Routers []Router `group:"routers,flatten"`
136 - ContentRouter []routing.ContentRouting `group:"content-routers,flatten"`
137 -}
138 -
139 -func DelegatedRouting(routers map[string]config.Router) interface{} {
140 - return func() (delegatedRouterOut, error) {
141 - out := delegatedRouterOut{}
142 -
143 - for _, v := range routers {
144 - if !v.Enabled.WithDefault(true) {
145 - continue
146 - }
147 -
148 - r, err := irouting.RoutingFromConfig(v)
149 - if err != nil {
150 - return out, err
151 - }
152 -
153 - out.Routers = append(out.Routers, Router{
154 - Routing: r,
155 - Priority: irouting.GetPriority(v.Parameters),
156 - })
157 -
158 - out.ContentRouter = append(out.ContentRouter, r)
159 - }
160 -
161 - return out, nil
162 - }
163 -}
164 -
132 type p2pOnlineContentRoutingIn struct {
133 fx.In
134
@@ -195,24 +162,23 @@ type p2pOnlineRoutingIn struct {
162 // Routing will get all routers obtained from different methods
163 // (delegated routers, pub-sub, and so on) and add them all together
164 // using a TieredRouter.
198 -func Routing(in p2pOnlineRoutingIn) irouting.TieredRouter {
165 +func Routing(in p2pOnlineRoutingIn) irouting.ProvideManyRouter {
166 routers := in.Routers
167
168 sort.SliceStable(routers, func(i, j int) bool {
169 return routers[i].Priority < routers[j].Priority
170 })
171
205 - irouters := make([]routing.Routing, len(routers))
206 - for i, v := range routers {
207 - irouters[i] = v.Routing
172 + var cRouters []*routinghelpers.ParallelRouter
173 + for _, v := range routers {
174 + cRouters = append(cRouters, &routinghelpers.ParallelRouter{
175 + Timeout: 5 * time.Minute,
176 + IgnoreError: true,
177 + Router: v.Routing,
178 + })
179 }
180
210 - return irouting.Tiered{
211 - Tiered: routinghelpers.Tiered{
212 - Routers: irouters,
213 - Validator: in.Validator,
214 - },
215 - }
181 + return routinghelpers.NewComposableParallel(cRouters)
182 }
183
184 // OfflineRouting provides a special Router to the routers list when we are creating a offline node.
core/node/libp2p/routingopt.go
+33
@@ -2,7 +2,10 @@ package libp2p
2
3 import (
4 "context"
5 +
6 "github.com/ipfs/go-datastore"
7 + "github.com/ipfs/kubo/config"
8 + irouting "github.com/ipfs/kubo/routing"
9 dht "github.com/libp2p/go-libp2p-kad-dht"
10 dual "github.com/libp2p/go-libp2p-kad-dht/dual"
11 record "github.com/libp2p/go-libp2p-record"
@@ -46,6 +49,36 @@ func constructDHTRouting(mode dht.ModeOpt) func(
49 }
50 }
51
52 +func ConstructDelegatedRouting(routers config.Routers, methods config.Methods, peerID string, addrs []string, privKey string) func(
53 + ctx context.Context,
54 + host host.Host,
55 + dstore datastore.Batching,
56 + validator record.Validator,
57 + bootstrapPeers ...peer.AddrInfo,
58 +) (routing.Routing, error) {
59 + return func(
60 + ctx context.Context,
61 + host host.Host,
62 + dstore datastore.Batching,
63 + validator record.Validator,
64 + bootstrapPeers ...peer.AddrInfo,
65 + ) (routing.Routing, error) {
66 + return irouting.Parse(routers, methods,
67 + &irouting.ExtraDHTParams{
68 + BootstrapPeers: bootstrapPeers,
69 + Host: host,
70 + Validator: validator,
71 + Datastore: dstore,
72 + Context: ctx,
73 + },
74 + &irouting.ExtraReframeParams{
75 + PeerID: peerID,
76 + Addrs: addrs,
77 + PrivKeyB64: privKey,
78 + })
79 + }
80 +}
81 +
82 func constructNilRouting(
83 ctx context.Context,
84 host host.Host,
core/node/provider.go
+4 -9
@@ -28,13 +28,13 @@ func ProviderQueue(mctx helpers.MetricsCtx, lc fx.Lifecycle, repo repo.Repo) (*q
28 }
29
30 // SimpleProvider creates new record provider
31 -func SimpleProvider(mctx helpers.MetricsCtx, lc fx.Lifecycle, queue *q.Queue, rt irouting.TieredRouter) provider.Provider {
31 +func SimpleProvider(mctx helpers.MetricsCtx, lc fx.Lifecycle, queue *q.Queue, rt irouting.ProvideManyRouter) provider.Provider {
32 return simple.NewProvider(helpers.LifecycleCtx(mctx, lc), queue, rt)
33 }
34
35 // SimpleReprovider creates new reprovider
36 func SimpleReprovider(reproviderInterval time.Duration) interface{} {
37 - return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, rt irouting.TieredRouter, keyProvider simple.KeyChanFunc) (provider.Reprovider, error) {
37 + return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, rt irouting.ProvideManyRouter, keyProvider simple.KeyChanFunc) (provider.Reprovider, error) {
38 return simple.NewReprovider(helpers.LifecycleCtx(mctx, lc), reproviderInterval, rt, keyProvider), nil
39 }
40 }
@@ -62,12 +62,7 @@ func SimpleProviderSys(isOnline bool) interface{} {
62
63 // BatchedProviderSys creates new provider system
64 func BatchedProviderSys(isOnline bool, reprovideInterval string) interface{} {
65 - return func(lc fx.Lifecycle, cr irouting.TieredRouter, q *q.Queue, keyProvider simple.KeyChanFunc, repo repo.Repo) (provider.System, error) {
66 - r := cr.ProvideMany()
67 - if r == nil {
68 - return nil, fmt.Errorf("BatchedProviderSys requires a content router that supports provideMany")
69 - }
70 -
65 + return func(lc fx.Lifecycle, cr irouting.ProvideManyRouter, q *q.Queue, keyProvider simple.KeyChanFunc, repo repo.Repo) (provider.System, error) {
66 reprovideIntervalDuration := kReprovideFrequency
67 if reprovideInterval != "" {
68 dur, err := time.ParseDuration(reprovideInterval)
@@ -78,7 +73,7 @@ func BatchedProviderSys(isOnline bool, reprovideInterval string) interface{} {
73 reprovideIntervalDuration = dur
74 }
75
81 - sys, err := batched.New(r, q,
76 + sys, err := batched.New(cr, q,
77 batched.ReproviderInterval(reprovideIntervalDuration),
78 batched.Datastore(repo.Datastore()),
79 batched.KeyProvider(keyProvider))
docs/changelogs/v0.16.md new
+94
@@ -0,0 +1,94 @@
1 +# Kubo changelog v0.16
2 +
3 +## v0.16.0
4 +
5 +### Overview
6 +
7 +Below is an outline of all that is in this release, so you get a sense of all that's included.
8 +
9 +- [Kubo changelog v0.16](#kubo-changelog-v016)
10 + - [v0.16.0](#v0160)
11 + - [Overview](#overview)
12 + - [🔦 Highlights](#-highlights)
13 + - [🛣️ More configurable delegated routing system](#️-more-configurable-delegated-routing-system)
14 + - [Changelog](#changelog)
15 + - [Contributors](#contributors)
16 +
17 +
18 +### 🔦 Highlights
19 +
20 +<!-- TODO -->
21 +
22 +#### 🛣️ More configurable delegated routing system
23 +
24 +Since Kubo v0.14.0 [Reframe protocol](https://github.com/ipfs/specs/tree/main/reframe#readme) has been supported as a new routing system.
25 +
26 +Now, we allow to configure several routers working together, so you can have several `reframe` and `dht` routers making queries. You can use the special `parallel` and `sequential` routers to fill your needs.
27 +
28 +Example configuration usage using the [Filecoin Network Indexer](https://docs.cid.contact/filecoin-network-indexer/overview) and the DHT, making first a query to the indexer, and timing out after 3 seconds.
29 +
30 +```
31 +$ ipfs config Routing.Type --json '"custom"'
32 +
33 +$ ipfs config Routing.Routers.CidContact --json '{
34 + "Type": "reframe",
35 + "Parameters": {
36 + "Endpoint": "https://cid.contact/reframe"
37 + }
38 +}'
39 +
40 +$ ipfs config Routing.Routers.WanDHT --json '{
41 + "Type": "dht",
42 + "Parameters": {
43 + "Mode": "auto",
44 + "PublicIPNetwork": true,
45 + "AcceleratedDHTClient": false
46 + }
47 +}'
48 +
49 +$ ipfs config Routing.Routers.ParallelHelper --json '{
50 + "Type": "parallel",
51 + "Parameters": {
52 + "Routers": [
53 + {
54 + "RouterName" : "CidContact",
55 + "IgnoreErrors" : true,
56 + "Timeout": "3s"
57 + },
58 + {
59 + "RouterName" : "WanDHT",
60 + "IgnoreErrors" : false,
61 + "Timeout": "5m",
62 + "ExecuteAfter": "2s"
63 + }
64 + ]
65 + }
66 +}'
67 +
68 +ipfs config Routing.Methods --json '{
69 + "find-peers": {
70 + "RouterName": "ParallelHelper"
71 + },
72 + "find-providers": {
73 + "RouterName": "ParallelHelper"
74 + },
75 + "get-ipns": {
76 + "RouterName": "ParallelHelper"
77 + },
78 + "provide": {
79 + "RouterName": "WanDHT"
80 + },
81 + "put-ipns": {
82 + "RouterName": "ParallelHelper"
83 + }
84 + }'
85 +
86 +```
87 +
88 +### Changelog
89 +
90 +<!-- TODO -->
91 +
92 +### Contributors
93 +
94 +<!-- TODO -->
\ No newline at end of file
docs/config.md
+117 -14
@@ -105,8 +105,8 @@ config file at runtime.
105 - [`Routing`](#routing)
106 - [`Routing.Routers`](#routingrouters)
107 - [`Routing.Routers: Type`](#routingrouters-type)
108 - - [`Routing.Routers: Enabled`](#routingrouters-enabled)
108 - [`Routing.Routers: Parameters`](#routingrouters-parameters)
109 + - [`Routing: Methods`](#routing-methods)
110 - [`Routing.Type`](#routingtype)
111 - [`Swarm`](#swarm)
112 - [`Swarm.AddrFilters`](#swarmaddrfilters)
@@ -1291,20 +1291,11 @@ It specifies the routing type that will be created.
1291 Currently supported types:
1292
1293 - `reframe` (delegated routing based on the [reframe protocol](https://github.com/ipfs/specs/tree/main/reframe#readme))
1294 -- <del>`dht`</del> (WIP, custom DHT will be added in a future release)
1294 +- `dht`
1295 +- `parallel` and `sequential`: Helpers that can be used to run several routers sequentially or in parallel.
1296
1297 Type: `string`
1298
1298 -#### `Routing.Routers: Enabled`
1299 -
1300 -**EXPERIMENTAL: `Routing.Routers` configuration may change in future release**
1301 -
1302 -Optional flag to disable the specified router without removing it from the configuration file.
1303 -
1304 -Default: `true`
1305 -
1306 -Type: `flag` (`null`/missing will apply the default)
1307 -
1299 #### `Routing.Routers: Parameters`
1300
1301 **EXPERIMENTAL: `Routing.Routers` configuration may change in future release**
@@ -1313,7 +1304,26 @@ Parameters needed to create the specified router. Supported params per router ty
1304
1305 Reframe:
1306 - `Endpoint` (mandatory): URL that will be used to connect to a specified router.
1316 - - `Priority` (optional): Priority is used when making a routing request. Small numbers represent more important routers. The default priority is 100000.
1307 +
1308 +DHT:
1309 + - `"Mode"`: Mode used by the DHT. Possible values: "server", "client", "auto"
1310 + - `"AcceleratedDHTClient"`: Set to `true` if you want to use the experimentalDHT.
1311 + - `"PublicIPNetwork"`: Set to `true` to create a `WAN` DHT. Set to `false` to create a `LAN` DHT.
1312 +
1313 +Parallel:
1314 + - `Routers`: A list of routers that will be executed in parallel:
1315 + - `Name:string`: Name of the router. It should be one of the previously added to `Routers` list.
1316 + - `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)` (`10s`, `1m`, `2h`). Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout.
1317 + - `ExecuteAfter:duration`: Providing this param will delay the execution of that router at the specified time. It accepts strings compatible with Go `time.ParseDuration(string)` (`10s`, `1m`, `2h`).
1318 + - `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred.
1319 + - `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)` (`10s`, `1m`, `2h`).
1320 +
1321 +Sequential:
1322 + - `Routers`: A list of routers that will be executed in order:
1323 + - `Name:string`: Name of the router. It should be one of the previously added to `Routers` list.
1324 + - `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout.
1325 + - `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred.
1326 + - `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)`.
1327
1328 **Examples:**
1329
@@ -1334,13 +1344,106 @@ Default: `{}` (use the safe implicit defaults)
1344
1345 Type: `object[string->string]`
1346
1347 +### `Routing: Methods`
1348 +
1349 +`Methods:map` will define which routers will be executed per method. The key will be the name of the method: `"provide"`, `"find-providers"`, `"find-peers"`, `"put-ipns"`, `"get-ipns"`. All methods must be added to the list.
1350 +
1351 +The value will contain:
1352 +- `RouterName:string`: Name of the router. It should be one of the previously added to `Routing.Routers` list.
1353 +
1354 +Type: `object[string->object]`
1355 +
1356 +**Examples:**
1357 +
1358 +To use the previously added `CidContact` reframe router on all methods:
1359 +
1360 +```console
1361 +$ ipfs config Routing.Methods --json '{
1362 + "find-peers": {
1363 + "RouterName": "CidContact"
1364 + },
1365 + "find-providers": {
1366 + "RouterName": "CidContact"
1367 + },
1368 + "get-ipns": {
1369 + "RouterName": "CidContact"
1370 + },
1371 + "provide": {
1372 + "RouterName": "CidContact"
1373 + },
1374 + "put-ipns": {
1375 + "RouterName": "CidContact"
1376 + }
1377 + }'
1378 +```
1379 +Complete example using 3 Routers, reframe, DHT and parallel.
1380 +
1381 +```
1382 +$ ipfs config Routing.Type --json '"custom"'
1383 +
1384 +$ ipfs config Routing.Routers.CidContact --json '{
1385 + "Type": "reframe",
1386 + "Parameters": {
1387 + "Endpoint": "https://cid.contact/reframe"
1388 + }
1389 +}'
1390 +
1391 +$ ipfs config Routing.Routers.WanDHT --json '{
1392 + "Type": "dht",
1393 + "Parameters": {
1394 + "Mode": "auto",
1395 + "PublicIPNetwork": true,
1396 + "AcceleratedDHTClient": false
1397 + }
1398 +}'
1399 +
1400 +$ ipfs config Routing.Routers.ParallelHelper --json '{
1401 + "Type": "parallel",
1402 + "Parameters": {
1403 + "Routers": [
1404 + {
1405 + "RouterName" : "CidContact",
1406 + "IgnoreErrors" : true,
1407 + "Timeout": "3s"
1408 + },
1409 + {
1410 + "RouterName" : "WanDHT",
1411 + "IgnoreErrors" : false,
1412 + "Timeout": "5m",
1413 + "ExecuteAfter": "2s"
1414 + }
1415 + ]
1416 + }
1417 +}'
1418 +
1419 +ipfs config Routing.Methods --json '{
1420 + "find-peers": {
1421 + "RouterName": "ParallelHelper"
1422 + },
1423 + "find-providers": {
1424 + "RouterName": "ParallelHelper"
1425 + },
1426 + "get-ipns": {
1427 + "RouterName": "ParallelHelper"
1428 + },
1429 + "provide": {
1430 + "RouterName": "WanDHT"
1431 + },
1432 + "put-ipns": {
1433 + "RouterName": "ParallelHelper"
1434 + }
1435 + }'
1436 +
1437 +```
1438 +
1439 ### `Routing.Type`
1440
1339 -There are two core routing options: "none" and "dht" (default).
1441 +There are three core routing options: "none", "dht" (default) and "custom".
1442
1443 * If set to "none", your node will use _no_ routing system. You'll have to
1444 explicitly connect to peers that have the content you're looking for.
1445 * If set to "dht" (or "dhtclient"/"dhtserver"), your node will use the IPFS DHT.
1446 +* If set to "custom", `Routing.Routers` will be used.
1447
1448 When the DHT is enabled, it can operate in two modes: client and server.
1449
docs/delegated-routing.md new
+462
@@ -0,0 +1,462 @@
1 +# New multi-router configuration system
2 +
3 +- Start Date: 2022-08-15
4 +- Related Issues:
5 + - https://github.com/ipfs/kubo/issues/9188
6 + - https://github.com/ipfs/kubo/issues/9079
7 +
8 +## Summary
9 +
10 +Previously we only used DHT for content routing and content providing. After kubo-0.14.0 release we added support for [delegated routing using Reframe protocol](https://github.com/ipfs/kubo/pull/8997).
11 +
12 +Now we need a better way to add different routers using different protocols like Reframe or DHT, and be able to configure them to cover different use cases.
13 +
14 +## Motivation
15 +
16 +The actual routing implementation is not enough. Some users needs to have more options when configuring the routing system. The new implementations should be able to:
17 +
18 +- [x] Be user-friendly and easy enough to configure, but also versatile
19 +- [x] Configurable Router execution order
20 + - [x] Delay some of the Router methods execution when they will be executed on parallel
21 +- [x] Configure which method of a giving router will be used
22 +- [x] Mark some router methods as mandatory to make the execution fails if that method fails
23 +
24 +## Detailed design
25 +
26 +### Configuration file description
27 +
28 +The `Routing` configuration section will contain the following keys:
29 +
30 +#### Type
31 +
32 +`Type` will be still in use to avoid complexity for the user that only wants to use Kubo with the default behavior. We are going to add a new type, `custom`, that will use the new router systems. `none` type will deactivate **all** routers, default dht and delegated ones.
33 +
34 +#### Routers
35 +
36 +`Routers` will be a key-value list of routers that will be available to use. The key is the router name and the value is all the needed configurations for that router. the `Type` will define the routing kind. The main router types will be `reframe` and `dht`, but we will implement two special routers used to execute a set of routers in parallel or sequentially: `parallel` router and `sequential` router.
37 +
38 +Depending on the routing type, it will use different parameters:
39 +
40 +##### Reframe
41 +
42 +Params:
43 +
44 +- `"Endpoint"`: URL endpoint implementing Reframe protocol.
45 +
46 +##### DHT
47 +
48 +Params:
49 +- `"Mode"`: Mode used by the DHT. Possible values: "server", "client", "auto"
50 +- `"AcceleratedDHTClient"`: Set to `true` if you want to use the experimentalDHT.
51 +- `"PublicIPNetwork"`: Set to `true` to create a `WAN` DHT. Set to `false` to create a `LAN` DHT.
52 +
53 +##### Parallel
54 +
55 +Params:
56 +- `Routers`: A list of routers that will be executed in parallel:
57 + - `Name:string`: Name of the router. It should be one of the previously added to `Routers` list.
58 + - `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout.
59 + - `ExecuteAfter:duration`: Providing this param will delay the execution of that router at the specified time. It accepts strings compatible with Go `time.ParseDuration(string)`.
60 + - `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred.
61 +- `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)`.
62 +##### Sequential
63 +
64 +Params:
65 +- `Routers`: A list of routers that will be executed in order:
66 + - `Name:string`: Name of the router. It should be one of the previously added to `Routers` list.
67 + - `Timeout:duration`: Local timeout. It accepts strings compatible with Go `time.ParseDuration(string)`. Time will start counting when this specific router is called, and it will stop when the router returns, or we reach the specified timeout.
68 + - `IgnoreErrors:bool`: It will specify if that router should be ignored if an error occurred.
69 +- `Timeout:duration`: Global timeout. It accepts strings compatible with Go `time.ParseDuration(string)`.
70 +#### Methods
71 +
72 +`Methods:map` will define which routers will be executed per method. The key will be the name of the method: `"provide"`, `"find-providers"`, `"find-peers"`, `"put-ipns"`, `"get-ipns"`. All methods must be added to the list. This will make configuration discoverable giving good errors to the user if a method is missing.
73 +
74 +The value will contain:
75 +- `RouterName:string`: Name of the router. It should be one of the previously added to `Routers` list.
76 +
77 +#### Configuration file example:
78 +
79 +```json
80 +"Routing": {
81 + "Type": "custom",
82 + "Routers": {
83 + "storetheindex": {
84 + "Type": "reframe",
85 + "Parameters": {
86 + "Endpoint": "https://cid.contact/reframe"
87 + }
88 + },
89 + "dht-lan": {
90 + "Type": "dht",
91 + "Parameters": {
92 + "Mode": "server",
93 + "PublicIPNetwork": false,
94 + "AcceleratedDHTClient": false
95 + }
96 + },
97 + "dht-wan": {
98 + "Type": "dht",
99 + "Parameters": {
100 + "Mode": "auto",
101 + "PublicIPNetwork": true,
102 + "AcceleratedDHTClient": false
103 + }
104 + },
105 + "find-providers-router": {
106 + "Type": "parallel",
107 + "Parameters": {
108 + "Routers": [
109 + {
110 + "RouterName": "dht-lan",
111 + "IgnoreErrors": true
112 + },
113 + {
114 + "RouterName": "dht-wan"
115 + },
116 + {
117 + "RouterName": "storetheindex"
118 + }
119 + ]
120 + }
121 + },
122 + "provide-router": {
123 + "Type": "parallel",
124 + "Parameters": {
125 + "Routers": [
126 + {
127 + "RouterName": "dht-lan",
128 + "IgnoreErrors": true
129 + },
130 + {
131 + "RouterName": "dht-wan",
132 + "ExecuteAfter": "100ms",
133 + "Timeout": "100ms"
134 + },
135 + {
136 + "RouterName": "storetheindex",
137 + "ExecuteAfter": "100ms"
138 + }
139 + ]
140 + }
141 + },
142 + "get-ipns-router": {
143 + "Type": "sequential",
144 + "Parameters": {
145 + "Routers": [
146 + {
147 + "RouterName": "dht-lan",
148 + "IgnoreErrors": true
149 + },
150 + {
151 + "RouterName": "dht-wan",
152 + "Timeout": "300ms"
153 + },
154 + {
155 + "RouterName": "storetheindex",
156 + "Timeout": "300ms"
157 + }
158 + ]
159 + }
160 + },
161 + "put-ipns-router": {
162 + "Type": "parallel",
163 + "Parameters": {
164 + "Routers": [
165 + {
166 + "RouterName": "dht-lan"
167 + },
168 + {
169 + "RouterName": "dht-wan"
170 + },
171 + {
172 + "RouterName": "storetheindex"
173 + }
174 + ]
175 + }
176 + }
177 + },
178 + "Methods": {
179 + "find-providers": {
180 + "RouterName": "find-providers-router"
181 + },
182 + "provide": {
183 + "RouterName": "provide-router"
184 + },
185 + "get-ipns": {
186 + "RouterName": "get-ipns-router"
187 + },
188 + "put-ipns": {
189 + "RouterName": "put-ipns-router"
190 + }
191 + }
192 +}
193 +```
194 +
195 +Added YAML for clarity:
196 +
197 +```yaml
198 +---
199 +Type: custom
200 +Routers:
201 + storetheindex:
202 + Type: reframe
203 + Parameters:
204 + Endpoint: https://cid.contact/reframe
205 + dht-lan:
206 + Type: dht
207 + Parameters:
208 + Mode: server
209 + PublicIPNetwork: false
210 + AcceleratedDHTClient: false
211 + dht-wan:
212 + Type: dht
213 + Parameters:
214 + Mode: auto
215 + PublicIPNetwork: true
216 + AcceleratedDHTClient: false
217 + find-providers-router:
218 + Type: parallel
219 + Parameters:
220 + Routers:
221 + - RouterName: dht-lan
222 + IgnoreErrors: true
223 + - RouterName: dht-wan
224 + - RouterName: storetheindex
225 + provide-router:
226 + Type: parallel
227 + Parameters:
228 + Routers:
229 + - RouterName: dht-lan
230 + IgnoreErrors: true
231 + - RouterName: dht-wan
232 + ExecuteAfter: 100ms
233 + Timeout: 100ms
234 + - RouterName: storetheindex
235 + ExecuteAfter: 100ms
236 + get-ipns-router:
237 + Type: sequential
238 + Parameters:
239 + Routers:
240 + - RouterName: dht-lan
241 + IgnoreErrors: true
242 + - RouterName: dht-wan
243 + Timeout: 300ms
244 + - RouterName: storetheindex
245 + Timeout: 300ms
246 + put-ipns-router:
247 + Type: parallel
248 + Parameters:
249 + Routers:
250 + - RouterName: dht-lan
251 + - RouterName: dht-wan
252 + - RouterName: storetheindex
253 +Methods:
254 + find-providers:
255 + RouterName: find-providers-router
256 + provide:
257 + RouterName: provide-router
258 + get-ipns:
259 + RouterName: get-ipns-router
260 + put-ipns:
261 + RouterName: put-ipns-router
262 +```
263 +
264 +### Error cases
265 + - If any of the routers fails, the output will be an error by default.
266 + - You can use `IgnoreErrors:true` to ignore errors for a specific router output
267 + - To avoid any error at the output, you must ignore all router errors.
268 +
269 +### Implementation Details
270 +
271 +#### Methods
272 +
273 +All routers must implement the `routing.Routing` interface:
274 +
275 +```go=
276 +type Routing interface {
277 + ContentRouting
278 + PeerRouting
279 + ValueStore
280 +
281 + Bootstrap(context.Context) error
282 +}
283 +```
284 +
285 +All methods involved:
286 +
287 +```go=
288 +type Routing interface {
289 + Provide(context.Context, cid.Cid, bool) error
290 + FindProvidersAsync(context.Context, cid.Cid, int) <-chan peer.AddrInfo
291 +
292 + FindPeer(context.Context, peer.ID) (peer.AddrInfo, error)
293 +
294 + PutValue(context.Context, string, []byte, ...Option) error
295 + GetValue(context.Context, string, ...Option) ([]byte, error)
296 + SearchValue(context.Context, string, ...Option) (<-chan []byte, error)
297 +
298 + Bootstrap(context.Context) error
299 +}
300 +```
301 +We can configure which methods will be used per routing implementation. Methods names used in the configuration file will be:
302 +
303 +- `Provide`: `"provide"`
304 +- `FindProvidersAsync`: `"find-providers"`
305 +- `FindPeer`: `"find-peers"`
306 +- `PutValue`: `"put-ipns"`
307 +- `GetValue`, `SearchValue`: `"get-ipns"`
308 +- `Bootstrap`: It will be always executed when needed.
309 +
310 +#### Routers
311 +
312 +We need to implement the `parallel` and `sequential` routers and stop using `routinghelpers.Tiered` router implementation.
313 +
314 +Add cycle detection to avoid to user some headaches.
315 +
316 +Also we need to implement an internal router, that will define the router used per method.
317 +
318 +#### Other considerations
319 +
320 +- We need to refactor how DHT routers are created to be able to use and add any amount of custom DHT routers.
321 +- We need to add a new `custom` router type to be able to use the new routing system.
322 +- Bitswap WANT broadcasting is not included on this document, but it can be added in next iterations.
323 +- This document will live in docs/design-notes for historical reasons and future reference.
324 +
325 +## Test fixtures
326 +
327 +As test fixtures we can add different use cases here and see how the configuration will look like.
328 +
329 +### Mimic previous dual DHT config
330 +
331 +```json
332 +"Routing": {
333 + "Type": "custom",
334 + "Routers": {
335 + "dht-lan": {
336 + "Type": "dht",
337 + "Parameters": {
338 + "Mode": "server",
339 + "PublicIPNetwork": false
340 + }
341 + },
342 + "dht-wan": {
343 + "Type": "dht",
344 + "Parameters": {
345 + "Mode": "auto",
346 + "PublicIPNetwork": true
347 + }
348 + },
349 + "parallel-dht-strict": {
350 + "Type": "parallel",
351 + "Parameters": {
352 + "Routers": [
353 + {
354 + "RouterName": "dht-lan"
355 + },
356 + {
357 + "RouterName": "dht-wan"
358 + }
359 + ]
360 + }
361 + },
362 + "parallel-dht": {
363 + "Type": "parallel",
364 + "Parameters": {
365 + "Routers": [
366 + {
367 + "RouterName": "dht-lan",
368 + "IgnoreError": true
369 + },
370 + {
371 + "RouterName": "dht-wan"
372 + }
373 + ]
374 + }
375 + }
376 + },
377 + "Methods": {
378 + "provide": {
379 + "RouterName": "dht-wan"
380 + },
381 + "find-providers": {
382 + "RouterName": "parallel-dht-strict"
383 + },
384 + "find-peers": {
385 + "RouterName": "parallel-dht-strict"
386 + },
387 + "get-ipns": {
388 + "RouterName": "parallel-dht"
389 + },
390 + "put-ipns": {
391 + "RouterName": "parallel-dht"
392 + }
393 + }
394 +}
395 +```
396 +
397 +Yaml representation for clarity:
398 +
399 +```yaml
400 +---
401 +Type: custom
402 +Routers:
403 + dht-lan:
404 + Type: dht
405 + Parameters:
406 + Mode: server
407 + PublicIPNetwork: false
408 + dht-wan:
409 + Type: dht
410 + Parameters:
411 + Mode: auto
412 + PublicIPNetwork: true
413 + parallel-dht-strict:
414 + Type: parallel
415 + Parameters:
416 + Routers:
417 + - RouterName: dht-lan
418 + - RouterName: dht-wan
419 + parallel-dht:
420 + Type: parallel
421 + Parameters:
422 + Routers:
423 + - RouterName: dht-lan
424 + IgnoreError: true
425 + - RouterName: dht-wan
426 +Methods:
427 + provide:
428 + RouterName: dht-wan
429 + find-providers:
430 + RouterName: parallel-dht-strict
431 + find-peers:
432 + RouterName: parallel-dht-strict
433 + get-ipns:
434 + RouterName: parallel-dht
435 + put-ipns:
436 + RouterName: parallel-dht
437 +
438 +```
439 +
440 +### Compatibility
441 +
442 +~~We need to create a config migration using [fs-repo-migrations](https://github.com/ipfs/fs-repo-migrations). We should remove the `Routing.Type` param and add the configuration specified [previously](#Mimic-previous-dual-DHT-config).~~
443 +
444 +We don't need to create any config migration! To avoid to the users the hassle of understanding how the new routing system works, we are gonna keep the old behavior. We will add the Type `custom` to make available the new Routing system.
445 +
446 +### Security
447 +
448 +No new security implications or considerations were found.
449 +
450 +### Alternatives
451 +
452 +I got ideas from all of the following links to create this design document:
453 +
454 +- https://github.com/ipfs/kubo/issues/9079#issuecomment-1211288268
455 +- https://github.com/ipfs/kubo/issues/9157
456 +- https://github.com/ipfs/kubo/issues/9079#issuecomment-1205000253
457 +- https://www.notion.so/pl-strflt/Delegated-Routing-Thoughts-very-very-WIP-0543bc51b1bd4d63a061b0f28e195d38
458 +- https://gist.github.com/guseggert/effa027ff4cbadd7f67598efb6704d12
459 +
460 +### Copyright
461 +
462 +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).
docs/examples/kubo-as-a-library/go.mod
+5 -5
@@ -68,7 +68,7 @@ require (
68 github.com/ipfs/go-cid v0.3.2 // indirect
69 github.com/ipfs/go-cidutil v0.1.0 // indirect
70 github.com/ipfs/go-datastore v0.6.0 // indirect
71 - github.com/ipfs/go-delegated-routing v0.3.0 // indirect
71 + github.com/ipfs/go-delegated-routing v0.6.0 // indirect
72 github.com/ipfs/go-ds-badger v0.3.0 // indirect
73 github.com/ipfs/go-ds-flatfs v0.5.1 // indirect
74 github.com/ipfs/go-ds-leveldb v0.5.0 // indirect
@@ -106,9 +106,9 @@ require (
106 github.com/ipfs/go-unixfs v0.4.0 // indirect
107 github.com/ipfs/go-unixfsnode v1.4.0 // indirect
108 github.com/ipfs/go-verifcid v0.0.2 // indirect
109 - github.com/ipld/edelweiss v0.1.4 // indirect
109 + github.com/ipld/edelweiss v0.2.0 // indirect
110 github.com/ipld/go-codec-dagpb v1.4.1 // indirect
111 - github.com/ipld/go-ipld-prime v0.17.0 // indirect
111 + github.com/ipld/go-ipld-prime v0.18.0 // indirect
112 github.com/jackpal/go-nat-pmp v1.0.2 // indirect
113 github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect
114 github.com/jbenet/goprocess v0.1.4 // indirect
@@ -127,7 +127,7 @@ require (
127 github.com/libp2p/go-libp2p-pubsub v0.6.1 // indirect
128 github.com/libp2p/go-libp2p-pubsub-router v0.5.0 // indirect
129 github.com/libp2p/go-libp2p-record v0.2.0 // indirect
130 - github.com/libp2p/go-libp2p-routing-helpers v0.2.3 // indirect
130 + github.com/libp2p/go-libp2p-routing-helpers v0.4.0 // indirect
131 github.com/libp2p/go-libp2p-xor v0.1.0 // indirect
132 github.com/libp2p/go-mplex v0.7.0 // indirect
133 github.com/libp2p/go-msgio v0.2.0 // indirect
@@ -209,7 +209,7 @@ require (
209 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
210 golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 // indirect
211 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
212 - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
212 + golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 // indirect
213 golang.org/x/text v0.3.7 // indirect
214 golang.org/x/tools v0.1.12 // indirect
215 golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
docs/examples/kubo-as-a-library/go.sum
+12 -7
@@ -477,6 +477,7 @@ github.com/ipfs/go-cid v0.0.6/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqg
477 github.com/ipfs/go-cid v0.0.7/go.mod h1:6Ux9z5e+HpkQdckYoX1PG/6xqKspzlEIR5SDmgqgC/I=
478 github.com/ipfs/go-cid v0.1.0/go.mod h1:rH5/Xv83Rfy8Rw6xG+id3DYAMUVmem1MowoKwdXmN2o=
479 github.com/ipfs/go-cid v0.2.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro=
480 +github.com/ipfs/go-cid v0.3.0/go.mod h1:P+HXFDF4CVhaVayiEb4wkAy7zBHxBwsJyt0Y5U6MLro=
481 github.com/ipfs/go-cid v0.3.2 h1:OGgOd+JCFM+y1DjWPmVH+2/4POtpDzwcr7VgnB7mZXc=
482 github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svoupw=
483 github.com/ipfs/go-cidutil v0.0.2/go.mod h1:ewllrvrxG6AMYStla3GD7Cqn+XYSLqjK0vc+086tB6s=
@@ -495,8 +496,8 @@ github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh7
496 github.com/ipfs/go-datastore v0.5.1/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
497 github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
498 github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
498 -github.com/ipfs/go-delegated-routing v0.3.0 h1:pF5apOJ/xdQkj22mRahW9GmSuCkgMLparKZWKJBO4CE=
499 -github.com/ipfs/go-delegated-routing v0.3.0/go.mod h1:2w79E1/G9YOaxyJJQgqIFSQaa/GdS2zSATEpK8aJUBM=
499 +github.com/ipfs/go-delegated-routing v0.6.0 h1:+M1siyTB2H4mHzEnbWjepQxlmKbapVWdbYLexSDODpg=
500 +github.com/ipfs/go-delegated-routing v0.6.0/go.mod h1:FJjhCChfcWK9z6OXo2jwKKJoxq1JlEWG7YTvwaA7UbI=
501 github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
502 github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
503 github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
@@ -653,8 +654,8 @@ github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0
654 github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPmI+GksBlLE8js=
655 github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY=
656 github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM=
656 -github.com/ipld/edelweiss v0.1.4 h1:g4+C2Ph+8SV2MCJBG3oRtetvxJYAS2WzlNGgsOY95iM=
657 -github.com/ipld/edelweiss v0.1.4/go.mod h1:JX1MR06BPcTOF+5xCYDLnylYkXS15iUN0/RXVSiUIQs=
657 +github.com/ipld/edelweiss v0.2.0 h1:KfAZBP8eeJtrLxLhi7r3N0cBCo7JmwSRhOJp3WSpNjk=
658 +github.com/ipld/edelweiss v0.2.0/go.mod h1:FJAzJRCep4iI8FOFlRriN9n0b7OuX3T/S9++NpBDmA4=
659 github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ=
660 github.com/ipld/go-car v0.4.0/go.mod h1:Uslcn4O9cBKK9wqHm/cLTFacg6RAPv6LZx2mxd2Ypl4=
661 github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI=
@@ -670,8 +671,9 @@ github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHt
671 github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM=
672 github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0=
673 github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA=
673 -github.com/ipld/go-ipld-prime v0.17.0 h1:+U2peiA3aQsE7mrXjD2nYZaZrCcakoz2Wge8K42Ld8g=
674 github.com/ipld/go-ipld-prime v0.17.0/go.mod h1:aYcKm5TIvGfY8P3QBKz/2gKcLxzJ1zDaD+o0bOowhgs=
675 +github.com/ipld/go-ipld-prime v0.18.0 h1:xUk7NUBSWHEXdjiOu2sLXouFJOMs0yoYzeI5RAqhYQo=
676 +github.com/ipld/go-ipld-prime v0.18.0/go.mod h1:735yXW548CKrLwVCYXzqx90p5deRJMVVxM9eJ4Qe+qE=
677 github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY=
678 github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
679 github.com/jackpal/go-nat-pmp v1.0.1/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc=
@@ -945,8 +947,9 @@ github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvN
947 github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y=
948 github.com/libp2p/go-libp2p-resource-manager v0.3.0/go.mod h1:K+eCkiapf+ey/LADO4TaMpMTP9/Qde/uLlrnRqV4PLQ=
949 github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys=
948 -github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY=
950 github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=
951 +github.com/libp2p/go-libp2p-routing-helpers v0.4.0 h1:b7y4aixQ7AwbqYfcOQ6wTw8DQvuRZeTAA0Od3YYN5yc=
952 +github.com/libp2p/go-libp2p-routing-helpers v0.4.0/go.mod h1:dYEAgkVhqho3/YKxfOEGdFMIcWfAFNlZX8iAIihYA2E=
953 github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0=
954 github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
955 github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
@@ -1286,6 +1289,7 @@ github.com/multiformats/go-multihash v0.0.14/go.mod h1:VdAWLKTwram9oKAatUcLxBNUj
1289 github.com/multiformats/go-multihash v0.0.15/go.mod h1:D6aZrWNLFTV/ynMpKsNtB40mJzmCl4jb1alC0OvHiHg=
1290 github.com/multiformats/go-multihash v0.0.16/go.mod h1:zhfEIgVnB/rPMfxgFw15ZmGoNaKyNUIE4IWHG/kC+Ag=
1291 github.com/multiformats/go-multihash v0.1.0/go.mod h1:RJlXsxt6vHGaia+S8We0ErjhojtKzPP2AH4+kYM7k84=
1292 +github.com/multiformats/go-multihash v0.2.0/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
1293 github.com/multiformats/go-multihash v0.2.1 h1:aem8ZT0VA2nCHHk7bPJ1BjUbHNciqZC/d16Vve9l108=
1294 github.com/multiformats/go-multihash v0.2.1/go.mod h1:WxoMcYG85AZVQUyRyo9s4wULvW5qrI9vb2Lt6evduFc=
1295 github.com/multiformats/go-multistream v0.0.1/go.mod h1:fJTiDfXJVmItycydCnNx4+wSzZ5NwG2FEVAI30fiovg=
@@ -1947,8 +1951,9 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
1951 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1952 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1953 golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1950 -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
1954 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1955 +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
1956 +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1957 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
1958 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
1959 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
go.mod
+5 -5
@@ -63,7 +63,7 @@ require (
63 github.com/ipld/go-car v0.4.0
64 github.com/ipld/go-car/v2 v2.4.0
65 github.com/ipld/go-codec-dagpb v1.4.1
66 - github.com/ipld/go-ipld-prime v0.17.0
66 + github.com/ipld/go-ipld-prime v0.18.0
67 github.com/jbenet/go-random v0.0.0-20190219211222-123a90aedc0c
68 github.com/jbenet/go-temp-err-catcher v0.1.0
69 github.com/jbenet/goprocess v0.1.4
@@ -77,7 +77,7 @@ require (
77 github.com/libp2p/go-libp2p-pubsub v0.6.1
78 github.com/libp2p/go-libp2p-pubsub-router v0.5.0
79 github.com/libp2p/go-libp2p-record v0.2.0
80 - github.com/libp2p/go-libp2p-routing-helpers v0.2.3
80 + github.com/libp2p/go-libp2p-routing-helpers v0.4.0
81 github.com/libp2p/go-libp2p-testing v0.12.0
82 github.com/libp2p/go-socket-activation v0.1.0
83 github.com/miekg/dns v1.1.50
@@ -111,12 +111,12 @@ require (
111 go.uber.org/zap v1.23.0
112 golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e
113 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
114 - golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab
114 + golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41
115 )
116
117 require (
118 github.com/benbjohnson/clock v1.3.0
119 - github.com/ipfs/go-delegated-routing v0.3.0
119 + github.com/ipfs/go-delegated-routing v0.6.0
120 github.com/ipfs/go-log/v2 v2.5.1
121 )
122
@@ -167,7 +167,7 @@ require (
167 github.com/ipfs/go-ipfs-ds-help v1.1.0 // indirect
168 github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
169 github.com/ipfs/go-peertaskqueue v0.7.1 // indirect
170 - github.com/ipld/edelweiss v0.1.4 // indirect
170 + github.com/ipld/edelweiss v0.2.0 // indirect
171 github.com/jackpal/go-nat-pmp v1.0.2 // indirect
172 github.com/klauspost/compress v1.15.10 // indirect
173 github.com/klauspost/cpuid/v2 v2.1.1 // indirect
go.sum
+10 -8
@@ -489,8 +489,8 @@ github.com/ipfs/go-datastore v0.4.5/go.mod h1:eXTcaaiN6uOlVCLS9GjJUJtlvJfM3xk23w
489 github.com/ipfs/go-datastore v0.5.0/go.mod h1:9zhEApYMTl17C8YDp7JmU7sQZi2/wqiYh73hakZ90Bk=
490 github.com/ipfs/go-datastore v0.6.0 h1:JKyz+Gvz1QEZw0LsX1IBn+JFCJQH4SJVFtM4uWU0Myk=
491 github.com/ipfs/go-datastore v0.6.0/go.mod h1:rt5M3nNbSO/8q1t4LNkLyUwRs8HupMeN/8O4Vn9YAT8=
492 -github.com/ipfs/go-delegated-routing v0.3.0 h1:pF5apOJ/xdQkj22mRahW9GmSuCkgMLparKZWKJBO4CE=
493 -github.com/ipfs/go-delegated-routing v0.3.0/go.mod h1:2w79E1/G9YOaxyJJQgqIFSQaa/GdS2zSATEpK8aJUBM=
492 +github.com/ipfs/go-delegated-routing v0.6.0 h1:+M1siyTB2H4mHzEnbWjepQxlmKbapVWdbYLexSDODpg=
493 +github.com/ipfs/go-delegated-routing v0.6.0/go.mod h1:FJjhCChfcWK9z6OXo2jwKKJoxq1JlEWG7YTvwaA7UbI=
494 github.com/ipfs/go-detect-race v0.0.1 h1:qX/xay2W3E4Q1U7d9lNs1sU9nvguX0a7319XbyQ6cOk=
495 github.com/ipfs/go-detect-race v0.0.1/go.mod h1:8BNT7shDZPo99Q74BpGMK+4D8Mn4j46UU0LZ723meps=
496 github.com/ipfs/go-ds-badger v0.0.2/go.mod h1:Y3QpeSFWQf6MopLTiZD+VT6IC1yZqaGmjvRcKeSGij8=
@@ -649,8 +649,8 @@ github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPm
649 github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY=
650 github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4=
651 github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM=
652 -github.com/ipld/edelweiss v0.1.4 h1:g4+C2Ph+8SV2MCJBG3oRtetvxJYAS2WzlNGgsOY95iM=
653 -github.com/ipld/edelweiss v0.1.4/go.mod h1:JX1MR06BPcTOF+5xCYDLnylYkXS15iUN0/RXVSiUIQs=
652 +github.com/ipld/edelweiss v0.2.0 h1:KfAZBP8eeJtrLxLhi7r3N0cBCo7JmwSRhOJp3WSpNjk=
653 +github.com/ipld/edelweiss v0.2.0/go.mod h1:FJAzJRCep4iI8FOFlRriN9n0b7OuX3T/S9++NpBDmA4=
654 github.com/ipld/go-car v0.4.0 h1:U6W7F1aKF/OJMHovnOVdst2cpQE5GhmHibQkAixgNcQ=
655 github.com/ipld/go-car v0.4.0/go.mod h1:Uslcn4O9cBKK9wqHm/cLTFacg6RAPv6LZx2mxd2Ypl4=
656 github.com/ipld/go-car/v2 v2.1.1/go.mod h1:+2Yvf0Z3wzkv7NeI69i8tuZ+ft7jyjPYIWZzeVNeFcI=
@@ -666,8 +666,8 @@ github.com/ipld/go-ipld-prime v0.11.0/go.mod h1:+WIAkokurHmZ/KwzDOMUuoeJgaRQktHt
666 github.com/ipld/go-ipld-prime v0.14.0/go.mod h1:9ASQLwUFLptCov6lIYc70GRB4V7UTyLD0IJtrDJe6ZM=
667 github.com/ipld/go-ipld-prime v0.14.1/go.mod h1:QcE4Y9n/ZZr8Ijg5bGPT0GqYWgZ1704nH0RDcQtgTP0=
668 github.com/ipld/go-ipld-prime v0.16.0/go.mod h1:axSCuOCBPqrH+gvXr2w9uAOulJqBPhHPT2PjoiiU1qA=
669 -github.com/ipld/go-ipld-prime v0.17.0 h1:+U2peiA3aQsE7mrXjD2nYZaZrCcakoz2Wge8K42Ld8g=
670 -github.com/ipld/go-ipld-prime v0.17.0/go.mod h1:aYcKm5TIvGfY8P3QBKz/2gKcLxzJ1zDaD+o0bOowhgs=
669 +github.com/ipld/go-ipld-prime v0.18.0 h1:xUk7NUBSWHEXdjiOu2sLXouFJOMs0yoYzeI5RAqhYQo=
670 +github.com/ipld/go-ipld-prime v0.18.0/go.mod h1:735yXW548CKrLwVCYXzqx90p5deRJMVVxM9eJ4Qe+qE=
671 github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73 h1:TsyATB2ZRRQGTwafJdgEUQkmjOExRV0DNokcihZxbnQ=
672 github.com/ipld/go-ipld-prime/storage/bsadapter v0.0.0-20211210234204-ce2a1c70cd73/go.mod h1:2PJ0JgxyB08t0b2WKrcuqI3di0V+5n6RS/LTUJhkoxY=
673 github.com/jackpal/gateway v1.0.5/go.mod h1:lTpwd4ACLXmpyiCTRtfiNyVnUmqT9RivzCDQetPfnjA=
@@ -936,8 +936,9 @@ github.com/libp2p/go-libp2p-record v0.2.0 h1:oiNUOCWno2BFuxt3my4i1frNrt7PerzB3qu
936 github.com/libp2p/go-libp2p-record v0.2.0/go.mod h1:I+3zMkvvg5m2OcSdoL0KPljyJyvNDFGKX7QdlpYUcwk=
937 github.com/libp2p/go-libp2p-resource-manager v0.1.5/go.mod h1:wJPNjeE4XQlxeidwqVY5G6DLOKqFK33u2n8blpl0I6Y=
938 github.com/libp2p/go-libp2p-routing v0.0.1/go.mod h1:N51q3yTr4Zdr7V8Jt2JIktVU+3xBBylx1MZeVA6t1Ys=
939 -github.com/libp2p/go-libp2p-routing-helpers v0.2.3 h1:xY61alxJ6PurSi+MXbywZpelvuU4U4p/gPTxjqCqTzY=
939 github.com/libp2p/go-libp2p-routing-helpers v0.2.3/go.mod h1:795bh+9YeoFl99rMASoiVgHdi5bjack0N1+AFAdbvBw=
940 +github.com/libp2p/go-libp2p-routing-helpers v0.4.0 h1:b7y4aixQ7AwbqYfcOQ6wTw8DQvuRZeTAA0Od3YYN5yc=
941 +github.com/libp2p/go-libp2p-routing-helpers v0.4.0/go.mod h1:dYEAgkVhqho3/YKxfOEGdFMIcWfAFNlZX8iAIihYA2E=
942 github.com/libp2p/go-libp2p-secio v0.0.3/go.mod h1:hS7HQ00MgLhRO/Wyu1bTX6ctJKhVpm+j2/S2A5UqYb0=
943 github.com/libp2p/go-libp2p-secio v0.1.0/go.mod h1:tMJo2w7h3+wN4pgU2LSYeiKPrfqBgkOsdiKK77hE7c8=
944 github.com/libp2p/go-libp2p-secio v0.2.0/go.mod h1:2JdZepB8J5V9mBp79BmwsaPQhRPNN2NrnB2lKQcdy6g=
@@ -1907,8 +1908,9 @@ golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBc
1908 golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1909 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1910 golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1910 -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
1911 golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1912 +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41 h1:ohgcoMbSofXygzo6AD2I1kz3BFmW1QArPYTtwEM3UXc=
1913 +golang.org/x/sys v0.0.0-20220915200043-7b5979e65e41/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1914 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
1915 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
1916 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
repo/fsrepo/migrations/ipfsfetcher/ipfsfetcher.go
+1 -1
@@ -188,7 +188,7 @@ func initTempNode(ctx context.Context, bootstrap []string, peers []peer.AddrInfo
188 }
189
190 // configure the temporary node
191 - cfg.Routing.Type = config.NewOptionalString("dhtclient")
191 + cfg.Routing.Type = "dhtclient"
192
193 // Disable listening for inbound connections
194 cfg.Addresses.Gateway = []string{}
routing/composer.go new
+74
@@ -0,0 +1,74 @@
1 +package routing
2 +
3 +import (
4 + "context"
5 +
6 + "github.com/hashicorp/go-multierror"
7 + "github.com/ipfs/go-cid"
8 + routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
9 + "github.com/libp2p/go-libp2p/core/peer"
10 + "github.com/libp2p/go-libp2p/core/routing"
11 + "github.com/multiformats/go-multihash"
12 +)
13 +
14 +var _ routinghelpers.ProvideManyRouter = &Composer{}
15 +var _ routing.Routing = &Composer{}
16 +
17 +type Composer struct {
18 + GetValueRouter routing.Routing
19 + PutValueRouter routing.Routing
20 + FindPeersRouter routing.Routing
21 + FindProvidersRouter routing.Routing
22 + ProvideRouter routing.Routing
23 +}
24 +
25 +func (c *Composer) Provide(ctx context.Context, cid cid.Cid, provide bool) error {
26 + return c.ProvideRouter.Provide(ctx, cid, provide)
27 +}
28 +
29 +func (c *Composer) ProvideMany(ctx context.Context, keys []multihash.Multihash) error {
30 + pmr, ok := c.ProvideRouter.(routinghelpers.ProvideManyRouter)
31 + if !ok {
32 + return nil
33 + }
34 +
35 + return pmr.ProvideMany(ctx, keys)
36 +}
37 +
38 +func (c *Composer) Ready() bool {
39 + pmr, ok := c.ProvideRouter.(routinghelpers.ProvideManyRouter)
40 + if !ok {
41 + return false
42 + }
43 +
44 + return pmr.Ready()
45 +}
46 +
47 +func (c *Composer) FindProvidersAsync(ctx context.Context, cid cid.Cid, count int) <-chan peer.AddrInfo {
48 + return c.FindProvidersRouter.FindProvidersAsync(ctx, cid, count)
49 +}
50 +
51 +func (c *Composer) FindPeer(ctx context.Context, pid peer.ID) (peer.AddrInfo, error) {
52 + return c.FindPeersRouter.FindPeer(ctx, pid)
53 +}
54 +
55 +func (c *Composer) PutValue(ctx context.Context, key string, val []byte, opts ...routing.Option) error {
56 + return c.PutValueRouter.PutValue(ctx, key, val, opts...)
57 +}
58 +
59 +func (c *Composer) GetValue(ctx context.Context, key string, opts ...routing.Option) ([]byte, error) {
60 + return c.GetValueRouter.GetValue(ctx, key, opts...)
61 +}
62 +
63 +func (c *Composer) SearchValue(ctx context.Context, key string, opts ...routing.Option) (<-chan []byte, error) {
64 + return c.GetValueRouter.SearchValue(ctx, key, opts...)
65 +}
66 +
67 +func (c *Composer) Bootstrap(ctx context.Context) error {
68 + errfp := c.FindPeersRouter.Bootstrap(ctx)
69 + errfps := c.FindProvidersRouter.Bootstrap(ctx)
70 + errgv := c.GetValueRouter.Bootstrap(ctx)
71 + errpv := c.PutValueRouter.Bootstrap(ctx)
72 + errp := c.ProvideRouter.Bootstrap(ctx)
73 + return multierror.Append(errfp, errfps, errgv, errpv, errp)
74 +}
routing/delegated.go
+271 -49
@@ -1,93 +1,315 @@
1 package routing
2
3 import (
4 - "strconv"
4 + "context"
5 + "encoding/base64"
6 + "errors"
7 + "fmt"
8 + "net/http"
9
10 + "github.com/ipfs/go-datastore"
11 drc "github.com/ipfs/go-delegated-routing/client"
12 drp "github.com/ipfs/go-delegated-routing/gen/proto"
13 + logging "github.com/ipfs/go-log"
14 "github.com/ipfs/kubo/config"
15 + dht "github.com/libp2p/go-libp2p-kad-dht"
16 + "github.com/libp2p/go-libp2p-kad-dht/dual"
17 + "github.com/libp2p/go-libp2p-kad-dht/fullrt"
18 + record "github.com/libp2p/go-libp2p-record"
19 routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
20 + ic "github.com/libp2p/go-libp2p/core/crypto"
21 + host "github.com/libp2p/go-libp2p/core/host"
22 + "github.com/libp2p/go-libp2p/core/peer"
23 "github.com/libp2p/go-libp2p/core/routing"
24 + ma "github.com/multiformats/go-multiaddr"
25 + "github.com/multiformats/go-multicodec"
26 )
27
13 -type TieredRouter interface {
14 - routing.Routing
15 - ProvideMany() ProvideMany
16 -}
28 +var log = logging.Logger("routing/delegated")
29
18 -var _ TieredRouter = &Tiered{}
30 +func Parse(routers config.Routers, methods config.Methods, extraDHT *ExtraDHTParams, extraReframe *ExtraReframeParams) (routing.Routing, error) {
31 + if err := methods.Check(); err != nil {
32 + return nil, err
33 + }
34
20 -// Tiered is a routing Tiered implementation providing some extra methods to fill
21 -// some special use cases when initializing the client.
22 -type Tiered struct {
23 - routinghelpers.Tiered
24 -}
35 + createdRouters := make(map[string]routing.Routing)
36 + finalRouter := &Composer{}
37
26 -// ProvideMany returns a ProvideMany implementation including all Routers that
27 -// implements ProvideMany
28 -func (ds Tiered) ProvideMany() ProvideMany {
29 - var pms []ProvideMany
30 - for _, r := range ds.Tiered.Routers {
31 - pm, ok := r.(ProvideMany)
32 - if !ok {
33 - continue
38 + // Create all needed routers from method names
39 + for mn, m := range methods {
40 + router, err := parse(make(map[string]bool), createdRouters, m.RouterName, routers, extraDHT, extraReframe)
41 + if err != nil {
42 + return nil, err
43 }
35 - pms = append(pms, pm)
36 - }
44
38 - if len(pms) == 0 {
39 - return nil
45 + switch mn {
46 + case config.MethodNamePutIPNS:
47 + finalRouter.PutValueRouter = router
48 + case config.MethodNameGetIPNS:
49 + finalRouter.GetValueRouter = router
50 + case config.MethodNameFindPeers:
51 + finalRouter.FindPeersRouter = router
52 + case config.MethodNameFindProviders:
53 + finalRouter.FindProvidersRouter = router
54 + case config.MethodNameProvide:
55 + finalRouter.ProvideRouter = router
56 + }
57 +
58 + log.Info("using method ", mn, " with router ", m.RouterName)
59 }
60
42 - return &ProvideManyWrapper{pms: pms}
61 + return finalRouter, nil
62 }
63
45 -const defaultPriority = 100000
64 +func parse(visited map[string]bool,
65 + createdRouters map[string]routing.Routing,
66 + routerName string,
67 + routersCfg config.Routers,
68 + extraDHT *ExtraDHTParams,
69 + extraReframe *ExtraReframeParams,
70 +) (routing.Routing, error) {
71 + // check if we already created it
72 + r, ok := createdRouters[routerName]
73 + if ok {
74 + return r, nil
75 + }
76
47 -// GetPriority extract priority from config params.
48 -// Small numbers represent more important routers.
49 -func GetPriority(params map[string]string) int {
50 - param := params[string(config.RouterParamPriority)]
51 - if param == "" {
52 - return defaultPriority
77 + // check if we are in a dep loop
78 + if visited[routerName] {
79 + return nil, fmt.Errorf("dependency loop creating router with name %q", routerName)
80 }
81
55 - p, err := strconv.Atoi(param)
56 - if err != nil {
57 - return defaultPriority
82 + // set node as visited
83 + visited[routerName] = true
84 +
85 + cfg, ok := routersCfg[routerName]
86 + if !ok {
87 + return nil, fmt.Errorf("config for router with name %q not found", routerName)
88 }
89
60 - return p
61 -}
90 + var router routing.Routing
91 + var err error
92 + switch cfg.Type {
93 + case config.RouterTypeReframe:
94 + router, err = reframeRoutingFromConfig(cfg.Router, extraReframe)
95 + case config.RouterTypeDHT:
96 + router, err = dhtRoutingFromConfig(cfg.Router, extraDHT)
97 + case config.RouterTypeParallel:
98 + crp := cfg.Parameters.(*config.ComposableRouterParams)
99 + var pr []*routinghelpers.ParallelRouter
100 + for _, cr := range crp.Routers {
101 + ri, err := parse(visited, createdRouters, cr.RouterName, routersCfg, extraDHT, extraReframe)
102 + if err != nil {
103 + return nil, err
104 + }
105 +
106 + pr = append(pr, &routinghelpers.ParallelRouter{
107 + Router: ri,
108 + IgnoreError: cr.IgnoreErrors,
109 + Timeout: cr.Timeout.Duration,
110 + ExecuteAfter: cr.ExecuteAfter.WithDefault(0),
111 + })
112 +
113 + }
114
63 -// RoutingFromConfig creates a Routing instance from the specified configuration.
64 -func RoutingFromConfig(c config.Router) (routing.Routing, error) {
65 - switch {
66 - case c.Type == string(config.RouterTypeReframe):
67 - return reframeRoutingFromConfig(c)
115 + router = routinghelpers.NewComposableParallel(pr)
116 + case config.RouterTypeSequential:
117 + crp := cfg.Parameters.(*config.ComposableRouterParams)
118 + var sr []*routinghelpers.SequentialRouter
119 + for _, cr := range crp.Routers {
120 + ri, err := parse(visited, createdRouters, cr.RouterName, routersCfg, extraDHT, extraReframe)
121 + if err != nil {
122 + return nil, err
123 + }
124 +
125 + sr = append(sr, &routinghelpers.SequentialRouter{
126 + Router: ri,
127 + IgnoreError: cr.IgnoreErrors,
128 + Timeout: cr.Timeout.Duration,
129 + })
130 +
131 + }
132 +
133 + router = routinghelpers.NewComposableSequential(sr)
134 default:
69 - return nil, &RouterTypeNotFoundError{c.Type}
135 + return nil, fmt.Errorf("unknown router type %q", cfg.Type)
136 }
137 +
138 + if err != nil {
139 + return nil, err
140 + }
141 +
142 + createdRouters[routerName] = router
143 +
144 + log.Info("created router ", routerName, " with params ", cfg.Parameters)
145 +
146 + return router, nil
147 +}
148 +
149 +type ExtraReframeParams struct {
150 + PeerID string
151 + Addrs []string
152 + PrivKeyB64 string
153 }
154
73 -func reframeRoutingFromConfig(conf config.Router) (routing.Routing, error) {
155 +func reframeRoutingFromConfig(conf config.Router, extraReframe *ExtraReframeParams) (routing.Routing, error) {
156 var dr drp.DelegatedRouting_Client
157
76 - param := string(config.RouterParamEndpoint)
77 - addr, ok := conf.Parameters[param]
78 - if !ok {
79 - return nil, NewParamNeededErr(param, conf.Type)
158 + params := conf.Parameters.(*config.ReframeRouterParams)
159 +
160 + if params.Endpoint == "" {
161 + return nil, NewParamNeededErr("Endpoint", conf.Type)
162 }
163
82 - dr, err := drp.New_DelegatedRouting_Client(addr)
164 + // Increase per-host connection pool since we are making lots of concurrent requests.
165 + transport := http.DefaultTransport.(*http.Transport).Clone()
166 + transport.MaxIdleConns = 500
167 + transport.MaxIdleConnsPerHost = 100
168 +
169 + delegateHTTPClient := &http.Client{
170 + Transport: transport,
171 + }
172 + dr, err := drp.New_DelegatedRouting_Client(params.Endpoint,
173 + drp.DelegatedRouting_Client_WithHTTPClient(delegateHTTPClient),
174 + )
175 if err != nil {
176 return nil, err
177 }
178
87 - c := drc.NewClient(dr)
179 + var c *drc.Client
180 +
181 + // this path is for tests only
182 + if extraReframe == nil {
183 + c, err = drc.NewClient(dr, nil, nil)
184 + if err != nil {
185 + return nil, err
186 + }
187 + } else {
188 + prov, err := createProvider(extraReframe.PeerID, extraReframe.Addrs)
189 + if err != nil {
190 + return nil, err
191 + }
192 +
193 + key, err := decodePrivKey(extraReframe.PrivKeyB64)
194 + if err != nil {
195 + return nil, err
196 + }
197 +
198 + c, err = drc.NewClient(dr, prov, key)
199 + if err != nil {
200 + return nil, err
201 + }
202 + }
203 +
204 crc := drc.NewContentRoutingClient(c)
205 return &reframeRoutingWrapper{
206 Client: c,
207 ContentRoutingClient: crc,
208 }, nil
209 }
210 +
211 +func decodePrivKey(keyB64 string) (ic.PrivKey, error) {
212 + pk, err := base64.StdEncoding.DecodeString(keyB64)
213 + if err != nil {
214 + return nil, err
215 + }
216 +
217 + return ic.UnmarshalPrivateKey(pk)
218 +}
219 +
220 +func createProvider(peerID string, addrs []string) (*drc.Provider, error) {
221 + pID, err := peer.Decode(peerID)
222 + if err != nil {
223 + return nil, err
224 + }
225 +
226 + var mas []ma.Multiaddr
227 + for _, a := range addrs {
228 + m, err := ma.NewMultiaddr(a)
229 + if err != nil {
230 + return nil, err
231 + }
232 +
233 + mas = append(mas, m)
234 + }
235 +
236 + return &drc.Provider{
237 + Peer: peer.AddrInfo{
238 + ID: pID,
239 + Addrs: mas,
240 + },
241 + ProviderProto: []drc.TransferProtocol{
242 + {Codec: multicodec.TransportBitswap},
243 + },
244 + }, nil
245 +}
246 +
247 +type ExtraDHTParams struct {
248 + BootstrapPeers []peer.AddrInfo
249 + Host host.Host
250 + Validator record.Validator
251 + Datastore datastore.Batching
252 + Context context.Context
253 +}
254 +
255 +func dhtRoutingFromConfig(conf config.Router, extra *ExtraDHTParams) (routing.Routing, error) {
256 + params, ok := conf.Parameters.(*config.DHTRouterParams)
257 + if !ok {
258 + return nil, errors.New("incorrect params for DHT router")
259 + }
260 +
261 + if params.AcceleratedDHTClient {
262 + return createFullRT(extra)
263 + }
264 +
265 + var mode dht.ModeOpt
266 + switch params.Mode {
267 + case config.DHTModeAuto:
268 + mode = dht.ModeAuto
269 + case config.DHTModeClient:
270 + mode = dht.ModeClient
271 + case config.DHTModeServer:
272 + mode = dht.ModeServer
273 + default:
274 + return nil, fmt.Errorf("invalid DHT mode: %q", params.Mode)
275 + }
276 +
277 + return createDHT(extra, params.PublicIPNetwork, mode)
278 +}
279 +
280 +func createDHT(params *ExtraDHTParams, public bool, mode dht.ModeOpt) (routing.Routing, error) {
281 + var opts []dht.Option
282 +
283 + if public {
284 + opts = append(opts, dht.QueryFilter(dht.PublicQueryFilter),
285 + dht.RoutingTableFilter(dht.PublicRoutingTableFilter),
286 + dht.RoutingTablePeerDiversityFilter(dht.NewRTPeerDiversityFilter(params.Host, 2, 3)))
287 + } else {
288 + opts = append(opts, dht.ProtocolExtension(dual.LanExtension),
289 + dht.QueryFilter(dht.PrivateQueryFilter),
290 + dht.RoutingTableFilter(dht.PrivateRoutingTableFilter))
291 + }
292 +
293 + opts = append(opts,
294 + dht.Concurrency(10),
295 + dht.Mode(mode),
296 + dht.Datastore(params.Datastore),
297 + dht.Validator(params.Validator),
298 + dht.BootstrapPeers(params.BootstrapPeers...))
299 +
300 + return dht.New(
301 + params.Context, params.Host, opts...,
302 + )
303 +}
304 +
305 +func createFullRT(params *ExtraDHTParams) (routing.Routing, error) {
306 + return fullrt.NewFullRT(params.Host,
307 + dht.DefaultPrefix,
308 + fullrt.DHTOption(
309 + dht.Validator(params.Validator),
310 + dht.Datastore(params.Datastore),
311 + dht.BootstrapPeers(params.BootstrapPeers...),
312 + dht.BucketSize(20),
313 + ),
314 + )
315 +}
routing/delegated_test.go
+197 -79
@@ -1,121 +1,239 @@
1 package routing
2
3 import (
4 - "context"
4 + "encoding/base64"
5 "testing"
6
7 - "github.com/ipfs/go-cid"
7 "github.com/ipfs/kubo/config"
9 - routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
10 - "github.com/libp2p/go-libp2p/core/peer"
11 - "github.com/libp2p/go-libp2p/core/routing"
12 - "github.com/multiformats/go-multihash"
8 + crypto "github.com/libp2p/go-libp2p/core/crypto"
9 + peer "github.com/libp2p/go-libp2p/core/peer"
10 "github.com/stretchr/testify/require"
11 )
12
16 -func TestPriority(t *testing.T) {
13 +func TestReframeRoutingFromConfig(t *testing.T) {
14 require := require.New(t)
18 - params := make(map[string]string)
19 - p := GetPriority(params)
15
21 - require.Equal(defaultPriority, p)
16 + r, err := reframeRoutingFromConfig(config.Router{
17 + Type: config.RouterTypeReframe,
18 + Parameters: &config.ReframeRouterParams{},
19 + }, nil)
20
23 - params[string(config.RouterParamPriority)] = "101"
24 -
25 - p = GetPriority(params)
26 -
27 - require.Equal(101, p)
28 -
29 - params[string(config.RouterParamPriority)] = "NAN"
30 -
31 - p = GetPriority(params)
32 -
33 - require.Equal(defaultPriority, p)
34 -}
21 + require.Nil(r)
22 + require.EqualError(err, "configuration param 'Endpoint' is needed for reframe delegated routing types")
23
36 -func TestRoutingFromConfig(t *testing.T) {
37 - require := require.New(t)
24 + r, err = reframeRoutingFromConfig(config.Router{
25 + Type: config.RouterTypeReframe,
26 + Parameters: &config.ReframeRouterParams{
27 + Endpoint: "test",
28 + },
29 + }, nil)
30
39 - r, err := RoutingFromConfig(config.Router{
40 - Type: "unknown",
41 - })
31 + require.NoError(err)
32 + require.NotNil(r)
33
43 - require.Nil(r)
44 - require.EqualError(err, "router type unknown is not supported")
34 + priv, pub, err := crypto.GenerateKeyPair(crypto.RSA, 2048)
35 + require.NoError(err)
36
46 - r, err = RoutingFromConfig(config.Router{
47 - Type: string(config.RouterTypeReframe),
48 - Parameters: make(map[string]string),
49 - })
37 + id, err := peer.IDFromPublicKey(pub)
38 + require.NoError(err)
39
51 - require.Nil(r)
52 - require.EqualError(err, "configuration param 'Endpoint' is needed for reframe delegated routing types")
40 + privM, err := crypto.MarshalPrivateKey(priv)
41 + require.NoError(err)
42
54 - r, err = RoutingFromConfig(config.Router{
55 - Type: string(config.RouterTypeReframe),
56 - Parameters: map[string]string{
57 - string(config.RouterParamEndpoint): "test",
43 + r, err = reframeRoutingFromConfig(config.Router{
44 + Type: config.RouterTypeReframe,
45 + Parameters: &config.ReframeRouterParams{
46 + Endpoint: "test",
47 },
48 + }, &ExtraReframeParams{
49 + PeerID: id.String(),
50 + Addrs: []string{"/ip4/0.0.0.0/tcp/4001"},
51 + PrivKeyB64: base64.StdEncoding.EncodeToString(privM),
52 })
53
54 require.NotNil(r)
55 require.NoError(err)
56 }
57
65 -func TestTieredRouter(t *testing.T) {
58 +func TestParser(t *testing.T) {
59 require := require.New(t)
60
68 - tr := &Tiered{
69 - Tiered: routinghelpers.Tiered{
70 - Routers: []routing.Routing{routinghelpers.Null{}},
61 + router, err := Parse(config.Routers{
62 + "r1": config.RouterParser{
63 + Router: config.Router{
64 + Type: config.RouterTypeReframe,
65 + Parameters: &config.ReframeRouterParams{
66 + Endpoint: "testEndpoint",
67 + },
68 + },
69 },
72 - }
73 -
74 - pm := tr.ProvideMany()
75 - require.Nil(pm)
76 -
77 - tr.Tiered.Routers = append(tr.Tiered.Routers, &dummyRouter{})
78 -
79 - pm = tr.ProvideMany()
80 - require.NotNil(pm)
81 -}
70 + "r2": config.RouterParser{
71 + Router: config.Router{
72 + Type: config.RouterTypeSequential,
73 + Parameters: &config.ComposableRouterParams{
74 + Routers: []config.ConfigRouter{
75 + {
76 + RouterName: "r1",
77 + },
78 + },
79 + },
80 + },
81 + },
82 + }, config.Methods{
83 + config.MethodNameFindPeers: config.Method{
84 + RouterName: "r1",
85 + },
86 + config.MethodNameFindProviders: config.Method{
87 + RouterName: "r1",
88 + },
89 + config.MethodNameGetIPNS: config.Method{
90 + RouterName: "r1",
91 + },
92 + config.MethodNamePutIPNS: config.Method{
93 + RouterName: "r2",
94 + },
95 + config.MethodNameProvide: config.Method{
96 + RouterName: "r2",
97 + },
98 + }, &ExtraDHTParams{}, nil)
99
83 -type dummyRouter struct {
84 -}
100 + require.NoError(err)
101
86 -func (dr *dummyRouter) Provide(context.Context, cid.Cid, bool) error {
87 - panic("not implemented")
102 + comp, ok := router.(*Composer)
103 + require.True(ok)
104
105 + require.Equal(comp.FindPeersRouter, comp.FindProvidersRouter)
106 + require.Equal(comp.ProvideRouter, comp.PutValueRouter)
107 }
108
91 -func (dr *dummyRouter) FindProvidersAsync(context.Context, cid.Cid, int) <-chan peer.AddrInfo {
92 - panic("not implemented")
93 -}
109 +func TestParserRecursive(t *testing.T) {
110 + require := require.New(t)
111
95 -func (dr *dummyRouter) FindPeer(context.Context, peer.ID) (peer.AddrInfo, error) {
96 - panic("not implemented")
97 -}
112 + router, err := Parse(config.Routers{
113 + "reframe1": config.RouterParser{
114 + Router: config.Router{
115 + Type: config.RouterTypeReframe,
116 + Parameters: &config.ReframeRouterParams{
117 + Endpoint: "testEndpoint1",
118 + },
119 + },
120 + },
121 + "reframe2": config.RouterParser{
122 + Router: config.Router{
123 + Type: config.RouterTypeReframe,
124 + Parameters: &config.ReframeRouterParams{
125 + Endpoint: "testEndpoint2",
126 + },
127 + },
128 + },
129 + "reframe3": config.RouterParser{
130 + Router: config.Router{
131 + Type: config.RouterTypeReframe,
132 + Parameters: &config.ReframeRouterParams{
133 + Endpoint: "testEndpoint3",
134 + },
135 + },
136 + },
137 + "composable1": config.RouterParser{
138 + Router: config.Router{
139 + Type: config.RouterTypeSequential,
140 + Parameters: &config.ComposableRouterParams{
141 + Routers: []config.ConfigRouter{
142 + {
143 + RouterName: "reframe1",
144 + },
145 + {
146 + RouterName: "reframe2",
147 + },
148 + },
149 + },
150 + },
151 + },
152 + "composable2": config.RouterParser{
153 + Router: config.Router{
154 + Type: config.RouterTypeParallel,
155 + Parameters: &config.ComposableRouterParams{
156 + Routers: []config.ConfigRouter{
157 + {
158 + RouterName: "composable1",
159 + },
160 + {
161 + RouterName: "reframe3",
162 + },
163 + },
164 + },
165 + },
166 + },
167 + }, config.Methods{
168 + config.MethodNameFindPeers: config.Method{
169 + RouterName: "composable2",
170 + },
171 + config.MethodNameFindProviders: config.Method{
172 + RouterName: "composable2",
173 + },
174 + config.MethodNameGetIPNS: config.Method{
175 + RouterName: "composable2",
176 + },
177 + config.MethodNamePutIPNS: config.Method{
178 + RouterName: "composable2",
179 + },
180 + config.MethodNameProvide: config.Method{
181 + RouterName: "composable2",
182 + },
183 + }, &ExtraDHTParams{}, nil)
184
99 -func (dr *dummyRouter) PutValue(context.Context, string, []byte, ...routing.Option) error {
100 - panic("not implemented")
101 -}
185 + require.NoError(err)
186
103 -func (dr *dummyRouter) GetValue(context.Context, string, ...routing.Option) ([]byte, error) {
104 - panic("not implemented")
105 -}
187 + _, ok := router.(*Composer)
188 + require.True(ok)
189
107 -func (dr *dummyRouter) SearchValue(context.Context, string, ...routing.Option) (<-chan []byte, error) {
108 - panic("not implemented")
190 }
191
111 -func (dr *dummyRouter) Bootstrap(context.Context) error {
112 - panic("not implemented")
113 -}
192 +func TestParserRecursiveLoop(t *testing.T) {
193 + require := require.New(t)
194
115 -func (dr *dummyRouter) ProvideMany(ctx context.Context, keys []multihash.Multihash) error {
116 - panic("not implemented")
117 -}
195 + _, err := Parse(config.Routers{
196 + "composable1": config.RouterParser{
197 + Router: config.Router{
198 + Type: config.RouterTypeSequential,
199 + Parameters: &config.ComposableRouterParams{
200 + Routers: []config.ConfigRouter{
201 + {
202 + RouterName: "composable2",
203 + },
204 + },
205 + },
206 + },
207 + },
208 + "composable2": config.RouterParser{
209 + Router: config.Router{
210 + Type: config.RouterTypeParallel,
211 + Parameters: &config.ComposableRouterParams{
212 + Routers: []config.ConfigRouter{
213 + {
214 + RouterName: "composable1",
215 + },
216 + },
217 + },
218 + },
219 + },
220 + }, config.Methods{
221 + config.MethodNameFindPeers: config.Method{
222 + RouterName: "composable2",
223 + },
224 + config.MethodNameFindProviders: config.Method{
225 + RouterName: "composable2",
226 + },
227 + config.MethodNameGetIPNS: config.Method{
228 + RouterName: "composable2",
229 + },
230 + config.MethodNamePutIPNS: config.Method{
231 + RouterName: "composable2",
232 + },
233 + config.MethodNameProvide: config.Method{
234 + RouterName: "composable2",
235 + },
236 + }, &ExtraDHTParams{}, nil)
237
119 -func (dr *dummyRouter) Ready() bool {
120 - panic("not implemented")
238 + require.ErrorContains(err, "dependency loop creating router with name \"composable2\"")
239 }
routing/error.go
+7 -11
@@ -1,13 +1,17 @@
1 package routing
2
3 -import "fmt"
3 +import (
4 + "fmt"
5 +
6 + "github.com/ipfs/kubo/config"
7 +)
8
9 type ParamNeededError struct {
10 ParamName string
7 - RouterType string
11 + RouterType config.RouterType
12 }
13
10 -func NewParamNeededErr(param, routing string) error {
14 +func NewParamNeededErr(param string, routing config.RouterType) error {
15 return &ParamNeededError{
16 ParamName: param,
17 RouterType: routing,
@@ -17,11 +21,3 @@ func NewParamNeededErr(param, routing string) error {
21 func (e *ParamNeededError) Error() string {
22 return fmt.Sprintf("configuration param '%v' is needed for %v delegated routing types", e.ParamName, e.RouterType)
23 }
20 -
21 -type RouterTypeNotFoundError struct {
22 - RouterType string
23 -}
24 -
25 -func (e *RouterTypeNotFoundError) Error() string {
26 - return fmt.Sprintf("router type %v is not supported", e.RouterType)
27 -}
routing/wrapper.go
+9 -33
@@ -5,13 +5,13 @@ import (
5
6 "github.com/ipfs/go-cid"
7 drc "github.com/ipfs/go-delegated-routing/client"
8 + routinghelpers "github.com/libp2p/go-libp2p-routing-helpers"
9 "github.com/libp2p/go-libp2p/core/peer"
10 "github.com/libp2p/go-libp2p/core/routing"
10 - "github.com/multiformats/go-multihash"
11 - "golang.org/x/sync/errgroup"
11 )
12
13 var _ routing.Routing = &reframeRoutingWrapper{}
14 +var _ routinghelpers.ProvideManyRouter = &reframeRoutingWrapper{}
15
16 // reframeRoutingWrapper is a wrapper needed to construct the routing.Routing interface from
17 // delegated-routing library.
@@ -20,6 +20,10 @@ type reframeRoutingWrapper struct {
20 *drc.ContentRoutingClient
21 }
22
23 +func (c *reframeRoutingWrapper) Provide(ctx context.Context, id cid.Cid, announce bool) error {
24 + return c.ContentRoutingClient.Provide(ctx, id, announce)
25 +}
26 +
27 func (c *reframeRoutingWrapper) FindProvidersAsync(ctx context.Context, cid cid.Cid, count int) <-chan peer.AddrInfo {
28 return c.ContentRoutingClient.FindProvidersAsync(ctx, cid, count)
29 }
@@ -32,35 +36,7 @@ func (c *reframeRoutingWrapper) FindPeer(ctx context.Context, id peer.ID) (peer.
36 return peer.AddrInfo{}, routing.ErrNotSupported
37 }
38
35 -type ProvideMany interface {
36 - ProvideMany(ctx context.Context, keys []multihash.Multihash) error
37 - Ready() bool
38 -}
39 -
40 -var _ ProvideMany = &ProvideManyWrapper{}
41 -
42 -type ProvideManyWrapper struct {
43 - pms []ProvideMany
44 -}
45 -
46 -func (pmw *ProvideManyWrapper) ProvideMany(ctx context.Context, keys []multihash.Multihash) error {
47 - var g errgroup.Group
48 - for _, pm := range pmw.pms {
49 - pm := pm
50 - g.Go(func() error {
51 - return pm.ProvideMany(ctx, keys)
52 - })
53 - }
54 -
55 - return g.Wait()
56 -}
57 -
58 -// Ready is ready if all providers are ready
59 -func (pmw *ProvideManyWrapper) Ready() bool {
60 - out := true
61 - for _, pm := range pmw.pms {
62 - out = out && pm.Ready()
63 - }
64 -
65 - return out
39 +type ProvideManyRouter interface {
40 + routinghelpers.ProvideManyRouter
41 + routing.Routing
42 }
routing/wrapper_test.go deleted
-101
@@ -1,101 +0,0 @@
1 -package routing
2 -
3 -import (
4 - "context"
5 - "errors"
6 - "testing"
7 -
8 - "github.com/multiformats/go-multihash"
9 -)
10 -
11 -func TestProvideManyWrapper_ProvideMany(t *testing.T) {
12 - type fields struct {
13 - pms []ProvideMany
14 - }
15 - tests := []struct {
16 - name string
17 - fields fields
18 - wantErr bool
19 - ready bool
20 - }{
21 - {
22 - name: "one provider",
23 - fields: fields{
24 - pms: []ProvideMany{
25 - newDummyProvideMany(true, false),
26 - },
27 - },
28 - wantErr: false,
29 - ready: true,
30 - },
31 - {
32 - name: "two providers, no errors and ready",
33 - fields: fields{
34 - pms: []ProvideMany{
35 - newDummyProvideMany(true, false),
36 - newDummyProvideMany(true, false),
37 - },
38 - },
39 - wantErr: false,
40 - ready: true,
41 - },
42 - {
43 - name: "two providers, no ready, no error",
44 - fields: fields{
45 - pms: []ProvideMany{
46 - newDummyProvideMany(true, false),
47 - newDummyProvideMany(false, false),
48 - },
49 - },
50 - wantErr: false,
51 - ready: false,
52 - },
53 - {
54 - name: "two providers, no ready, and one erroing",
55 - fields: fields{
56 - pms: []ProvideMany{
57 - newDummyProvideMany(true, false),
58 - newDummyProvideMany(false, true),
59 - },
60 - },
61 - wantErr: true,
62 - ready: false,
63 - },
64 - }
65 - for _, tt := range tests {
66 - t.Run(tt.name, func(t *testing.T) {
67 - pmw := &ProvideManyWrapper{
68 - pms: tt.fields.pms,
69 - }
70 - if err := pmw.ProvideMany(context.Background(), nil); (err != nil) != tt.wantErr {
71 - t.Errorf("ProvideManyWrapper.ProvideMany() error = %v, wantErr %v", err, tt.wantErr)
72 - }
73 -
74 - if ready := pmw.Ready(); ready != tt.ready {
75 - t.Errorf("ProvideManyWrapper.Ready() unexpected output = %v, want %v", ready, tt.ready)
76 - }
77 - })
78 - }
79 -}
80 -
81 -func newDummyProvideMany(ready, failProviding bool) *dummyProvideMany {
82 - return &dummyProvideMany{
83 - ready: ready,
84 - failProviding: failProviding,
85 - }
86 -}
87 -
88 -type dummyProvideMany struct {
89 - ready, failProviding bool
90 -}
91 -
92 -func (dpm *dummyProvideMany) ProvideMany(ctx context.Context, keys []multihash.Multihash) error {
93 - if dpm.failProviding {
94 - return errors.New("error providing many")
95 - }
96 -
97 - return nil
98 -}
99 -func (dpm *dummyProvideMany) Ready() bool {
100 - return dpm.ready
101 -}
test/sharness/t0041-ping.sh
+1 -1
@@ -27,7 +27,7 @@ test_expect_success "test ping other" '
27
28 test_expect_success "test ping unreachable peer" '
29 printf "Looking up peer %s\n" "$BAD_PEER" > bad_ping_exp &&
30 - printf "Error: peer lookup failed: routing: not found\n" >> bad_ping_exp &&
30 + printf "PING QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJx.\nPing error: routing: not found\nError: ping failed\n" >> bad_ping_exp &&
31 ! ipfsi 0 ping -n2 -- "$BAD_PEER" > bad_ping_actual 2>&1 &&
32 test_cmp bad_ping_exp bad_ping_actual
33 '
test/sharness/t0701-delegated-routing-reframe.sh
+68
@@ -66,13 +66,81 @@ test_expect_success "no routers means findprovs returns no results" '
66
67 test_kill_ipfs_daemon
68
69 +ipfs config Routing.Type --json '"custom"' || exit 1
70 +ipfs config Routing.Methods --json '{
71 + "find-peers": {
72 + "RouterName": "TestDelegatedRouter"
73 + },
74 + "find-providers": {
75 + "RouterName": "TestDelegatedRouter"
76 + },
77 + "get-ipns": {
78 + "RouterName": "TestDelegatedRouter"
79 + },
80 + "provide": {
81 + "RouterName": "TestDelegatedRouter"
82 + }
83 + }' || exit 1
84 +
85 +test_expect_success "missing method params makes daemon fails" '
86 + echo "Error: constructing the node (see log for full detail): method name \"put-ipns\" is missing from Routing.Methods config param" > expected_error &&
87 + GOLOG_LOG_LEVEL=fatal ipfs daemon 2> actual_error || exit 0 &&
88 + test_cmp expected_error actual_error
89 +'
90 +
91 +ipfs config Routing.Methods --json '{
92 + "find-peers": {
93 + "RouterName": "TestDelegatedRouter"
94 + },
95 + "find-providers": {
96 + "RouterName": "TestDelegatedRouter"
97 + },
98 + "get-ipns": {
99 + "RouterName": "TestDelegatedRouter"
100 + },
101 + "provide": {
102 + "RouterName": "TestDelegatedRouter"
103 + },
104 + "put-ipns": {
105 + "RouterName": "TestDelegatedRouter"
106 + },
107 + "NOT_SUPPORTED": {
108 + "RouterName": "TestDelegatedRouter"
109 + }
110 + }' || exit 1
111 +
112 +test_expect_success "having wrong methods makes daemon fails" '
113 + echo "Error: constructing the node (see log for full detail): method name \"NOT_SUPPORTED\" is not a supported method on Routing.Methods config param" > expected_error &&
114 + GOLOG_LOG_LEVEL=fatal ipfs daemon 2> actual_error || exit 0 &&
115 + test_cmp expected_error actual_error
116 +'
117 +
118 # set Routing config to only use delegated routing via mocked reframe endpoint
119 +
120 +ipfs config Routing.Type --json '"custom"' || exit 1
121 ipfs config Routing.Routers.TestDelegatedRouter --json '{
122 "Type": "reframe",
123 "Parameters": {
124 "Endpoint": "http://127.0.0.1:5098/reframe"
125 }
126 }' || exit 1
127 +ipfs config Routing.Methods --json '{
128 + "find-peers": {
129 + "RouterName": "TestDelegatedRouter"
130 + },
131 + "find-providers": {
132 + "RouterName": "TestDelegatedRouter"
133 + },
134 + "get-ipns": {
135 + "RouterName": "TestDelegatedRouter"
136 + },
137 + "provide": {
138 + "RouterName": "TestDelegatedRouter"
139 + },
140 + "put-ipns": {
141 + "RouterName": "TestDelegatedRouter"
142 + }
143 + }' || exit 1
144
145 test_expect_success "adding reframe endpoint to Routing.Routers config works" '
146 echo "http://127.0.0.1:5098/reframe" > expected &&