Skip to content

Commit 0fd7374

Browse files
authoredJan 21, 2019
Merge pull request #5789 from ipfs/kevina/multibase4
Add global option to specify the multibase encoding (server side)
2 parents de0bbb0 + 19d8f62 commit 0fd7374

33 files changed

+905
-178
lines changed
 

‎core/commands/add.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ You can now check what blocks have been created by:
174174
return fmt.Errorf("unrecognized hash function: %s", strings.ToLower(hashFunStr))
175175
}
176176

177+
enc, err := cmdenv.GetCidEncoder(req)
178+
if err != nil {
179+
return err
180+
}
181+
177182
events := make(chan interface{}, adderOutChanSize)
178183

179184
opts := []options.UnixfsAddOption{
@@ -226,7 +231,7 @@ You can now check what blocks have been created by:
226231

227232
h := ""
228233
if output.Path != nil {
229-
h = output.Path.Cid().String()
234+
h = enc.Encode(output.Path.Cid())
230235
}
231236

232237
res.Emit(&AddEvent{

‎core/commands/bitswap.go

+11-4
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
peer "gx/ipfs/QmY5Grm8pJdiSSVsYxx4uNRgweY72EmYwuSDbRnbFok3iY/go-libp2p-peer"
1313
bitswap "gx/ipfs/QmYoGLuLwTUv1SYBmsw1EVNC9MyLVUxwxzXYtKgAGHyEfw/go-bitswap"
1414
decision "gx/ipfs/QmYoGLuLwTUv1SYBmsw1EVNC9MyLVUxwxzXYtKgAGHyEfw/go-bitswap/decision"
15-
cidutil "gx/ipfs/QmbfKu17LbMWyGUxHEUns9Wf5Dkm8PT6be4uPhTkk4YvaV/go-cidutil"
15+
cidutil "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil"
1616
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
1717
)
1818

@@ -74,12 +74,15 @@ Print out all blocks currently on the bitswap wantlist for the local peer.`,
7474
},
7575
Encoders: cmds.EncoderMap{
7676
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *KeyList) error {
77+
enc, err := cmdenv.GetLowLevelCidEncoder(req)
78+
if err != nil {
79+
return err
80+
}
7781
// sort the keys first
7882
cidutil.Sort(out.Keys)
7983
for _, key := range out.Keys {
80-
fmt.Fprintln(w, key)
84+
fmt.Fprintln(w, enc.Encode(key))
8185
}
82-
8386
return nil
8487
}),
8588
},
@@ -115,6 +118,10 @@ var bitswapStatCmd = &cmds.Command{
115118
},
116119
Encoders: cmds.EncoderMap{
117120
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s *bitswap.Stat) error {
121+
enc, err := cmdenv.GetLowLevelCidEncoder(req)
122+
if err != nil {
123+
return err
124+
}
118125
fmt.Fprintln(w, "bitswap status")
119126
fmt.Fprintf(w, "\tprovides buffer: %d / %d\n", s.ProvideBufLen, bitswap.HasBlockBufferSize)
120127
fmt.Fprintf(w, "\tblocks received: %d\n", s.BlocksReceived)
@@ -125,7 +132,7 @@ var bitswapStatCmd = &cmds.Command{
125132
fmt.Fprintf(w, "\tdup data received: %s\n", humanize.Bytes(s.DupDataReceived))
126133
fmt.Fprintf(w, "\twantlist [%d keys]\n", len(s.Wantlist))
127134
for _, k := range s.Wantlist {
128-
fmt.Fprintf(w, "\t\t%s\n", k.String())
135+
fmt.Fprintf(w, "\t\t%s\n", enc.Encode(k))
129136
}
130137
fmt.Fprintf(w, "\tpartners [%d]\n", len(s.Peers))
131138
for _, p := range s.Peers {

‎core/commands/cid.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
1111
cmds "gx/ipfs/QmWGm4AbZEbnmdgVTza52MSNpEmBdFVqzmAysRbjrRyGbH/go-ipfs-cmds"
1212
verifcid "gx/ipfs/QmYMQuypUbgsdNHmuCBSUJV6wdQVsBHRivNAp3efHJwZJD/go-verifcid"
13-
cidutil "gx/ipfs/QmbfKu17LbMWyGUxHEUns9Wf5Dkm8PT6be4uPhTkk4YvaV/go-cidutil"
13+
cidutil "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil"
1414
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
1515
mbase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase"
1616
mhash "gx/ipfs/QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW/go-multihash"

‎core/commands/cmdenv/cidbase.go

+107
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
package cmdenv
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
8+
cmds "gx/ipfs/QmWGm4AbZEbnmdgVTza52MSNpEmBdFVqzmAysRbjrRyGbH/go-ipfs-cmds"
9+
cidenc "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil/cidenc"
10+
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
11+
mbase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase"
12+
)
13+
14+
var OptionCidBase = cmdkit.StringOption("cid-base", "Multibase encoding used for version 1 CIDs in output.")
15+
var OptionUpgradeCidV0InOutput = cmdkit.BoolOption("upgrade-cidv0-in-output", "Upgrade version 0 to version 1 CIDs in output.")
16+
17+
// GetCidEncoder processes the `cid-base` and `output-cidv1` options and
18+
// returns a encoder to use based on those parameters.
19+
func GetCidEncoder(req *cmds.Request) (cidenc.Encoder, error) {
20+
return getCidBase(req, true)
21+
}
22+
23+
// GetLowLevelCidEncoder is like GetCidEncoder but meant to be used by
24+
// lower level commands. It differs from GetCidEncoder in that CIDv0
25+
// are not, by default, auto-upgraded to CIDv1.
26+
func GetLowLevelCidEncoder(req *cmds.Request) (cidenc.Encoder, error) {
27+
return getCidBase(req, false)
28+
}
29+
30+
func getCidBase(req *cmds.Request, autoUpgrade bool) (cidenc.Encoder, error) {
31+
base, _ := req.Options[OptionCidBase.Name()].(string)
32+
upgrade, upgradeDefined := req.Options[OptionUpgradeCidV0InOutput.Name()].(bool)
33+
34+
e := cidenc.Default()
35+
36+
if base != "" {
37+
var err error
38+
e.Base, err = mbase.EncoderByName(base)
39+
if err != nil {
40+
return e, err
41+
}
42+
if autoUpgrade {
43+
e.Upgrade = true
44+
}
45+
}
46+
47+
if upgradeDefined {
48+
e.Upgrade = upgrade
49+
}
50+
51+
return e, nil
52+
}
53+
54+
// CidBaseDefined returns true if the `cid-base` option is specified
55+
// on the command line
56+
func CidBaseDefined(req *cmds.Request) bool {
57+
base, _ := req.Options["cid-base"].(string)
58+
return base != ""
59+
}
60+
61+
// CidEncoderFromPath creates a new encoder that is influenced from
62+
// the encoded Cid in a Path. For CidV0 the multibase from the base
63+
// encoder is used and automatic upgrades are disabled. For CidV1 the
64+
// multibase from the CID is used and upgrades are enabled.
65+
//
66+
// This logic is intentionally fuzzy and will match anything of the form
67+
// `CidLike`, `CidLike/...`, or `/namespace/CidLike/...`.
68+
//
69+
// For example:
70+
//
71+
// * Qm...
72+
// * Qm.../...
73+
// * /ipfs/Qm...
74+
// * /ipns/bafybeiahnxfi7fpmr5wtxs2imx4abnyn7fdxeiox7xxjem6zuiioqkh6zi/...
75+
// * /bzz/bafybeiahnxfi7fpmr5wtxs2imx4abnyn7fdxeiox7xxjem6zuiioqkh6zi/...
76+
func CidEncoderFromPath(p string) (cidenc.Encoder, error) {
77+
components := strings.SplitN(p, "/", 4)
78+
79+
var maybeCid string
80+
if components[0] != "" {
81+
// No leading slash, first component is likely CID-like.
82+
maybeCid = components[0]
83+
} else if len(components) < 3 {
84+
// Not enough components to include a CID.
85+
return cidenc.Encoder{}, fmt.Errorf("no cid in path: %s", p)
86+
} else {
87+
maybeCid = components[2]
88+
}
89+
c, err := cid.Decode(maybeCid)
90+
if err != nil {
91+
// Ok, not a CID-like thing. Keep the current encoder.
92+
return cidenc.Encoder{}, fmt.Errorf("no cid in path: %s", p)
93+
}
94+
if c.Version() == 0 {
95+
// Version 0, use the base58 non-upgrading encoder.
96+
return cidenc.Default(), nil
97+
}
98+
99+
// Version 1+, extract multibase encoding.
100+
encoding, _, err := mbase.Decode(maybeCid)
101+
if err != nil {
102+
// This should be impossible, we've already decoded the cid.
103+
panic(fmt.Sprintf("BUG: failed to get multibase decoder for CID %s", maybeCid))
104+
}
105+
106+
return cidenc.Encoder{Base: mbase.MustNewEncoder(encoding), Upgrade: true}, nil
107+
}

‎core/commands/cmdenv/cidbase_test.go

+73
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package cmdenv
2+
3+
import (
4+
"testing"
5+
6+
cidenc "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil/cidenc"
7+
mbase "gx/ipfs/QmekxXDhCxCJRNuzmHreuaT3BsuJcsjcXWNrtV9C8DRHtd/go-multibase"
8+
)
9+
10+
func TestEncoderFromPath(t *testing.T) {
11+
test := func(path string, expected cidenc.Encoder) {
12+
actual, err := CidEncoderFromPath(path)
13+
if err != nil {
14+
t.Error(err)
15+
}
16+
if actual != expected {
17+
t.Errorf("CidEncoderFromPath(%s) failed: expected %#v but got %#v", path, expected, actual)
18+
}
19+
}
20+
p := "QmRqVG8VGdKZ7KARqR96MV7VNHgWvEQifk94br5HpURpfu"
21+
enc := cidenc.Default()
22+
test(p, enc)
23+
test(p+"/a", enc)
24+
test(p+"/a/b", enc)
25+
test(p+"/a/b/", enc)
26+
test(p+"/a/b/c", enc)
27+
test("/ipfs/"+p, enc)
28+
test("/ipfs/"+p+"/b", enc)
29+
30+
p = "zb2rhfkM4FjkMLaUnygwhuqkETzbYXnUDf1P9MSmdNjW1w1Lk"
31+
enc = cidenc.Encoder{
32+
Base: mbase.MustNewEncoder(mbase.Base58BTC),
33+
Upgrade: true,
34+
}
35+
test(p, enc)
36+
test(p+"/a", enc)
37+
test(p+"/a/b", enc)
38+
test(p+"/a/b/", enc)
39+
test(p+"/a/b/c", enc)
40+
test("/ipfs/"+p, enc)
41+
test("/ipfs/"+p+"/b", enc)
42+
test("/ipld/"+p, enc)
43+
test("/ipns/"+p, enc) // even IPNS should work.
44+
45+
p = "bafyreifrcnyjokuw4i4ggkzg534tjlc25lqgt3ttznflmyv5fftdgu52hm"
46+
enc = cidenc.Encoder{
47+
Base: mbase.MustNewEncoder(mbase.Base32),
48+
Upgrade: true,
49+
}
50+
test(p, enc)
51+
test("/ipfs/"+p, enc)
52+
test("/ipld/"+p, enc)
53+
54+
for _, badPath := range []string{
55+
"/ipld/",
56+
"/ipld",
57+
"/ipld//",
58+
"ipld//",
59+
"ipld",
60+
"",
61+
"ipns",
62+
"/ipfs/asdf",
63+
"/ipfs/...",
64+
"...",
65+
"abcdefg",
66+
"boo",
67+
} {
68+
_, err := CidEncoderFromPath(badPath)
69+
if err == nil {
70+
t.Errorf("expected error extracting encoder from bad path: %s", badPath)
71+
}
72+
}
73+
}

‎core/commands/dag/dag.go

+26-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
cmds "gx/ipfs/QmWGm4AbZEbnmdgVTza52MSNpEmBdFVqzmAysRbjrRyGbH/go-ipfs-cmds"
1515
files "gx/ipfs/QmXWZCd8jfaHmt4UDSnjKmGcrQMw95bDGWqEeVLVJjoANX/go-ipfs-files"
1616
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
17+
cidenc "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil/cidenc"
1718
cmdkit "gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
1819
mh "gx/ipfs/QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW/go-multihash"
1920
)
@@ -144,7 +145,11 @@ into an object of the specified format.
144145
Type: OutputObject{},
145146
Encoders: cmds.EncoderMap{
146147
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *OutputObject) error {
147-
fmt.Fprintln(w, out.Cid.String())
148+
enc, err := cmdenv.GetLowLevelCidEncoder(req)
149+
if err != nil {
150+
return err
151+
}
152+
fmt.Fprintln(w, enc.Encode(out.Cid))
148153
return nil
149154
}),
150155
},
@@ -227,7 +232,26 @@ var DagResolveCmd = &cmds.Command{
227232
},
228233
Encoders: cmds.EncoderMap{
229234
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *ResolveOutput) error {
230-
p := out.Cid.String()
235+
var (
236+
enc cidenc.Encoder
237+
err error
238+
)
239+
switch {
240+
case !cmdenv.CidBaseDefined(req):
241+
// Not specified, check the path.
242+
enc, err = cmdenv.CidEncoderFromPath(req.Arguments[0])
243+
if err == nil {
244+
break
245+
}
246+
// Nope, fallback on the default.
247+
fallthrough
248+
default:
249+
enc, err = cmdenv.GetLowLevelCidEncoder(req)
250+
if err != nil {
251+
return err
252+
}
253+
}
254+
p := enc.Encode(out.Cid)
231255
if out.RemPath != "" {
232256
p = path.Join([]string{p, out.RemPath})
233257
}

‎core/commands/files.go

+17-6
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ import (
1717
"gx/ipfs/QmP9eu5X5Ax8169jNWqAJcc42mdZgzLR1aKCEzqhNoBLKk/go-mfs"
1818
"gx/ipfs/QmPSBJL4momYnE7DcUyk2DVhD6rH488ZmHBGLbxNdhU44K/go-humanize"
1919
ft "gx/ipfs/QmQXze9tG878pa4Euya4rrDpyTNX3kQe4dhCaBzBozGgpe/go-unixfs"
20-
"gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
20+
cid "gx/ipfs/QmR8BauakNcBa3RbE4nbQu76PDiJgoQgz8AJdhJuiU4TAw/go-cid"
2121
dag "gx/ipfs/QmTQdH4848iTVCJmKXYyRiK72HufWTLYQQ8iN3JaQ8K1Hq/go-merkledag"
2222
"gx/ipfs/QmWGm4AbZEbnmdgVTza52MSNpEmBdFVqzmAysRbjrRyGbH/go-ipfs-cmds"
2323
bservice "gx/ipfs/QmYPZzd9VqmJDwxUnThfeSbV1Y5o53aVPDijTB7j7rS9Ep/go-blockservice"
2424
"gx/ipfs/QmYZwey1thDTynSrvd6qQkX24UpTka6TFhQ2v569UpoqxD/go-ipfs-exchange-offline"
2525
ipld "gx/ipfs/QmcKKBwfz6FyQdHR2jsXrrF6XeSBXYL86anmWNewpFpoF5/go-ipld-format"
2626
logging "gx/ipfs/QmcuXC5cxs79ro2cUuHs4HQ2bkDLJUYokwL8aivcX6HW3C/go-log"
27+
cidenc "gx/ipfs/QmdPQx9fvN5ExVwMhRmh7YpCQJzJrFhd1AjVBwJmRMFJeX/go-cidutil/cidenc"
2728
"gx/ipfs/Qmde5VP1qUkyQXKCfmEUA7bP64V2HAptbJ7phuPp7jXWwg/go-ipfs-cmdkit"
2829
mh "gx/ipfs/QmerPMzPk1mJVowm8KgmoknWa4yCYvvugMPsgWmDNUvDLW/go-multihash"
2930
)
@@ -136,6 +137,11 @@ var filesStatCmd = &cmds.Command{
136137

137138
withLocal, _ := req.Options[filesWithLocalOptionName].(bool)
138139

140+
enc, err := cmdenv.GetCidEncoder(req)
141+
if err != nil {
142+
return err
143+
}
144+
139145
var dagserv ipld.DAGService
140146
if withLocal {
141147
// an offline DAGService will not fetch from the network
@@ -152,7 +158,7 @@ var filesStatCmd = &cmds.Command{
152158
return err
153159
}
154160

155-
o, err := statNode(nd)
161+
o, err := statNode(nd, enc)
156162
if err != nil {
157163
return err
158164
}
@@ -217,7 +223,7 @@ func statGetFormatOptions(req *cmds.Request) (string, error) {
217223
}
218224
}
219225

220-
func statNode(nd ipld.Node) (*statOutput, error) {
226+
func statNode(nd ipld.Node, enc cidenc.Encoder) (*statOutput, error) {
221227
c := nd.Cid()
222228

223229
cumulsize, err := nd.Size()
@@ -243,15 +249,15 @@ func statNode(nd ipld.Node) (*statOutput, error) {
243249
}
244250

245251
return &statOutput{
246-
Hash: c.String(),
252+
Hash: enc.Encode(c),
247253
Blocks: len(nd.Links()),
248254
Size: d.FileSize(),
249255
CumulativeSize: cumulsize,
250256
Type: ndtype,
251257
}, nil
252258
case *dag.RawNode:
253259
return &statOutput{
254-
Hash: c.String(),
260+
Hash: enc.Encode(c),
255261
Blocks: 0,
256262
Size: cumulsize,
257263
CumulativeSize: cumulsize,
@@ -433,6 +439,11 @@ Examples:
433439

434440
long, _ := req.Options[longOptionName].(bool)
435441

442+
enc, err := cmdenv.GetCidEncoder(req)
443+
if err != nil {
444+
return err
445+
}
446+
436447
switch fsn := fsn.(type) {
437448
case *mfs.Directory:
438449
if !long {
@@ -470,7 +481,7 @@ Examples:
470481
if err != nil {
471482
return err
472483
}
473-
out.Entries[0].Hash = nd.Cid().String()
484+
out.Entries[0].Hash = enc.Encode(nd.Cid())
474485
}
475486
return cmds.EmitOnce(res, out)
476487
default:

0 commit comments

Comments
 (0)
Please sign in to comment.