diff --git a/core/commands/resolve.go b/core/commands/resolve.go index a603f6acf2c9..f87b7b8d6a33 100644 --- a/core/commands/resolve.go +++ b/core/commands/resolve.go @@ -7,18 +7,16 @@ import ( "strings" "time" - "github.com/ipfs/go-ipfs/core" cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv" e "github.com/ipfs/go-ipfs/core/commands/e" ncmd "github.com/ipfs/go-ipfs/core/commands/name" + coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" + "github.com/ipfs/go-ipfs/core/coreapi/interface/options" ns "github.com/ipfs/go-ipfs/namesys" - nsopts "github.com/ipfs/go-ipfs/namesys/opts" path "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path" - uio "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/io" "gx/ipfs/QmPTfgFTo9PFr1PvPKyKoeMgBvYPh6cX3aDP7DHKVbnCbi/go-ipfs-cmds" "gx/ipfs/QmSP88ryZkHSRn1fnngAaV2Vcn63WUJzAavnRM9CVdU1Ky/go-ipfs-cmdkit" - resolver "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path/resolver" ) var ResolveCmd = &cmds.Command{ @@ -66,11 +64,11 @@ Resolve the value of an IPFS DAG path: }, Options: []cmdkit.Option{ cmdkit.BoolOption("recursive", "r", "Resolve until the result is an IPFS name."), - cmdkit.UintOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."), + cmdkit.IntOption("dht-record-count", "dhtrc", "Number of records to request for DHT resolution."), cmdkit.StringOption("dht-timeout", "dhtt", "Max time to collect values during DHT resolution eg \"30s\". Pass 0 for no timeout."), }, Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) { - n, err := cmdenv.GetNode(env) + api, err := cmdenv.GetApi(env) if err != nil { res.SetError(err, cmdkit.ErrNormal) return @@ -83,9 +81,10 @@ Resolve the value of an IPFS DAG path: if strings.HasPrefix(name, "/ipns/") && !recursive { rc, rcok := req.Options["dht-record-count"].(int) dhtt, dhttok := req.Options["dht-timeout"].(string) - ropts := []nsopts.ResolveOpt{nsopts.Depth(1)} + ropts := []options.NameResolveOption{options.Name.Depth(1)} + if rcok { - ropts = append(ropts, nsopts.DhtRecordCount(uint(rc))) + ropts = append(ropts, options.Name.DhtRecordCount(rc)) } if dhttok { d, err := time.ParseDuration(dhtt) @@ -97,37 +96,32 @@ Resolve the value of an IPFS DAG path: res.SetError(errors.New("DHT timeout value must be >= 0"), cmdkit.ErrNormal) return } - ropts = append(ropts, nsopts.DhtTimeout(d)) + ropts = append(ropts, options.Name.DhtTimeout(d)) } - p, err := n.Namesys.Resolve(req.Context, name, ropts...) + p, err := api.Name().Resolve(req.Context, name, ropts...) // ErrResolveRecursion is fine if err != nil && err != ns.ErrResolveRecursion { res.SetError(err, cmdkit.ErrNormal) return } - cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: p}) + cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.Path(p.String())}) return } // else, ipfs path or ipns with recursive flag - p, err := path.ParsePath(name) + p, err := coreiface.ParsePath(name) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - r := &resolver.Resolver{ - DAG: n.DAG, - ResolveOnce: uio.ResolveUnixfsOnce, - } - - node, err := core.Resolve(req.Context, n.Namesys, r, p) + rp, err := api.ResolvePath(req.Context, p) if err != nil { res.SetError(err, cmdkit.ErrNormal) return } - c := node.Cid() + c := rp.Cid() cmds.EmitOnce(res, &ncmd.ResolvedPath{Path: path.FromCid(c)}) }, diff --git a/core/coreapi/interface/options/name.go b/core/coreapi/interface/options/name.go index 48aecf18ba82..9ba4a8770e15 100644 --- a/core/coreapi/interface/options/name.go +++ b/core/coreapi/interface/options/name.go @@ -14,9 +14,12 @@ type NamePublishSettings struct { } type NameResolveSettings struct { - Recursive bool - Local bool - Cache bool + Depth int + Local bool + Cache bool + + DhtRecordCount int + DhtTimeout time.Duration } type NamePublishOption func(*NamePublishSettings) error @@ -40,9 +43,12 @@ func NamePublishOptions(opts ...NamePublishOption) (*NamePublishSettings, error) func NameResolveOptions(opts ...NameResolveOption) (*NameResolveSettings, error) { options := &NameResolveSettings{ - Recursive: false, - Local: false, - Cache: true, + Depth: 1, + Local: false, + Cache: true, + + DhtRecordCount: 16, + DhtTimeout: time.Minute, } for _, opt := range opts { @@ -80,11 +86,11 @@ func (nameOpts) Key(key string) NamePublishOption { } } -// Recursive is an option for Name.Resolve which specifies whether to perform a +// Depth is an option for Name.Resolve which specifies the maximum depth of a // recursive lookup. Default value is false -func (nameOpts) Recursive(recursive bool) NameResolveOption { +func (nameOpts) Depth(depth int) NameResolveOption { return func(settings *NameResolveSettings) error { - settings.Recursive = recursive + settings.Depth = depth return nil } } @@ -106,3 +112,22 @@ func (nameOpts) Cache(cache bool) NameResolveOption { return nil } } + +// DhtRecordCount is an option for Name.Resolve which specifies how many records +// we want to validate before selecting the best one (newest). Note that setting +// this value too low will have security implications +func (nameOpts) DhtRecordCount(rc int) NameResolveOption { + return func(settings *NameResolveSettings) error { + settings.DhtRecordCount = rc + return nil + } +} + +// DhtTimeout is an option for Name.Resolve which specifies timeout for +// DHT lookup +func (nameOpts) DhtTimeout(timeout time.Duration) NameResolveOption { + return func(settings *NameResolveSettings) error { + settings.DhtTimeout = timeout + return nil + } +} diff --git a/core/coreapi/name.go b/core/coreapi/name.go index 79b785f11121..f2909c3f85f0 100644 --- a/core/coreapi/name.go +++ b/core/coreapi/name.go @@ -119,9 +119,10 @@ func (api *NameAPI) Resolve(ctx context.Context, name string, opts ...caopts.Nam name = "/ipns/" + name } - var ropts []nsopts.ResolveOpt - if !options.Recursive { - ropts = append(ropts, nsopts.Depth(1)) + ropts := []nsopts.ResolveOpt{ + nsopts.Depth(uint(options.Depth)), + nsopts.DhtRecordCount(uint(options.DhtRecordCount)), + nsopts.DhtTimeout(options.DhtTimeout), } output, err := resolver.Resolve(ctx, name, ropts...) diff --git a/core/coreapi/path.go b/core/coreapi/path.go index cba68aeeac29..7d7e1487fa43 100644 --- a/core/coreapi/path.go +++ b/core/coreapi/path.go @@ -1,53 +1,44 @@ package coreapi import ( - context "context" - fmt "fmt" + "context" + "fmt" gopath "path" - core "github.com/ipfs/go-ipfs/core" + "github.com/ipfs/go-ipfs/core" coreiface "github.com/ipfs/go-ipfs/core/coreapi/interface" - namesys "github.com/ipfs/go-ipfs/namesys" uio "gx/ipfs/QmPL8bYtbACcSFFiSr4s2du7Na382NxRADR8hC7D9FkEA2/go-unixfs/io" ipfspath "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path" - resolver "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path/resolver" + "gx/ipfs/QmX7uSbkNz76yNwBhuwYwRbhihLnJqM73VTCjS3UMJud9A/go-path/resolver" - cid "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid" + "gx/ipfs/QmPSQnBKM9g7BaUcZCvswUJVscQ1ipjmwxN5PXCjkp9EQ7/go-cid" ipld "gx/ipfs/QmdDXJs4axxefSPgK6Y1QhpJWKuDPnGJiqgq4uncb4rFHL/go-ipld-format" ) // ResolveNode resolves the path `p` using Unixfs resolver, gets and returns the // resolved Node. func (api *CoreAPI) ResolveNode(ctx context.Context, p coreiface.Path) (ipld.Node, error) { - return resolveNode(ctx, api.node.DAG, api.node.Namesys, p) -} - -// ResolvePath resolves the path `p` using Unixfs resolver, returns the -// resolved path. -func (api *CoreAPI) ResolvePath(ctx context.Context, p coreiface.Path) (coreiface.ResolvedPath, error) { - return resolvePath(ctx, api.node.DAG, api.node.Namesys, p) -} - -func resolveNode(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSystem, p coreiface.Path) (ipld.Node, error) { - rp, err := resolvePath(ctx, ng, nsys, p) + rp, err := api.ResolvePath(ctx, p) if err != nil { return nil, err } - node, err := ng.Get(ctx, rp.Cid()) + node, err := api.node.DAG.Get(ctx, rp.Cid()) if err != nil { return nil, err } return node, nil } -func resolvePath(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSystem, p coreiface.Path) (coreiface.ResolvedPath, error) { +// ResolvePath resolves the path `p` using Unixfs resolver, returns the +// resolved path. +func (api *CoreAPI) ResolvePath(ctx context.Context, p coreiface.Path) (coreiface.ResolvedPath, error) { if _, ok := p.(coreiface.ResolvedPath); ok { return p.(coreiface.ResolvedPath), nil } ipath := ipfspath.Path(p.String()) - ipath, err := core.ResolveIPNS(ctx, nsys, ipath) + ipath, err := core.ResolveIPNS(ctx, api.node.Namesys, ipath) if err == core.ErrNoNamesys { return nil, coreiface.ErrOffline } else if err != nil { @@ -66,7 +57,7 @@ func resolvePath(ctx context.Context, ng ipld.NodeGetter, nsys namesys.NameSyste } r := &resolver.Resolver{ - DAG: ng, + DAG: api.node.DAG, ResolveOnce: resolveOnce, } diff --git a/core/coreapi/unixfs.go b/core/coreapi/unixfs.go index 1798336dbdb6..eb76e24ffef2 100644 --- a/core/coreapi/unixfs.go +++ b/core/coreapi/unixfs.go @@ -32,7 +32,7 @@ func (api *UnixfsAPI) Add(ctx context.Context, r io.Reader) (coreiface.ResolvedP func (api *UnixfsAPI) Cat(ctx context.Context, p coreiface.Path) (coreiface.Reader, error) { dget := api.node.DAG // TODO: use a session here once routing perf issues are resolved - dagnode, err := resolveNode(ctx, dget, api.node.Namesys, p) + dagnode, err := api.core().ResolveNode(ctx, p) if err != nil { return nil, err } diff --git a/core/coreapi/unixfs_test.go b/core/coreapi/unixfs_test.go index 7af4d9a1986c..b6cebf8e7945 100644 --- a/core/coreapi/unixfs_test.go +++ b/core/coreapi/unixfs_test.go @@ -87,8 +87,14 @@ func makeAPISwarm(ctx context.Context, fullIdentity bool, n int) ([]*core.IpfsNo node, err := core.NewNode(ctx, &core.BuildCfg{ Repo: r, Host: mock.MockHostOption(mn), - Online: fullIdentity, + Online: fullIdentity && n > 1, }) + if fullIdentity && n == 1 { + if err := node.SetupOfflineRouting(); err != nil { + return nil, nil, err + } + } + if err != nil { return nil, nil, err }