Skip to content

Commit 7b5fe80

Browse files
schomatislidel
andauthored
fix(cmds): CIDv1 and correct multicodecs in 'block put' and 'cid codecs' (#8568)
BREAKING CHANGES: - see #8568 (comment) Co-authored-by: Marcin Rataj <[email protected]>
1 parent 67fdb6e commit 7b5fe80

File tree

9 files changed

+204
-58
lines changed

9 files changed

+204
-58
lines changed

CHANGELOG.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
11
# go-ipfs changelog
22

3+
## v0.13 (DRAFT)
4+
5+
### BREAKING CHANGES
6+
7+
- `ipfs block put` command produces CIDv1 with `raw` codec by default now
8+
- `ipfs block put --cid-codec` makes `block put` return CID with alternative codec
9+
- this impacts only the returned CID, it does not trigger any validation or data transformation
10+
- codec names are validated against tables from https://github.com/multiformats/go-multicodec
11+
- `ipfs block put --format` is deprecated. It used incorrect codec names and should be avoided for new deployments. Use it only if you need the old, invalid behavior, namely:
12+
- `ipfs block put --format=v0` will produce CIDv0 (implicit dag-pb)
13+
- `ipfs block put --format=cbor` will produce CIDv1 with dag-cbor (!)
14+
- `ipfs block put --format=protobuf` will produce CIDv1 with dag-pb (!)
15+
- `ipfs cid codecs` command
16+
- it now lists codecs from https://github.com/multiformats/go-multicodec
17+
- `ipfs cid codecs --supported` can be passed to only show codecs supported in various go-ipfs commands
18+
19+
320
## v0.12.2 and v0.11.1 2022-04-08
421

522
This patch release fixes a security issue wherein traversing some malformed DAGs can cause the node to panic.

core/commands/block.go

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ var BlockCmd = &cmds.Command{
3131
Tagline: "Interact with raw IPFS blocks.",
3232
ShortDescription: `
3333
'ipfs block' is a plumbing command used to manipulate raw IPFS blocks.
34-
Reads from stdin or writes to stdout, and <key> is a base58 encoded
35-
multihash.
34+
Reads from stdin or writes to stdout. A block is identified by a Multihash
35+
passed with a valid CID.
3636
`,
3737
},
3838

@@ -51,14 +51,14 @@ var blockStatCmd = &cmds.Command{
5151
'ipfs block stat' is a plumbing command for retrieving information
5252
on raw IPFS blocks. It outputs the following to stdout:
5353
54-
Key - the base58 encoded multihash
54+
Key - the CID of the block
5555
Size - the size of the block in bytes
5656
5757
`,
5858
},
5959

6060
Arguments: []cmds.Argument{
61-
cmds.StringArg("key", true, false, "The base58 multihash of an existing block to stat.").EnableStdin(),
61+
cmds.StringArg("cid", true, false, "The CID of an existing block to stat.").EnableStdin(),
6262
},
6363
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
6464
api, err := cmdenv.GetApi(env, req)
@@ -90,12 +90,12 @@ var blockGetCmd = &cmds.Command{
9090
Tagline: "Get a raw IPFS block.",
9191
ShortDescription: `
9292
'ipfs block get' is a plumbing command for retrieving raw IPFS blocks.
93-
It outputs to stdout, and <key> is a base58 encoded multihash.
93+
It takes a <cid>, and outputs the block to stdout.
9494
`,
9595
},
9696

9797
Arguments: []cmds.Argument{
98-
cmds.StringArg("key", true, false, "The base58 multihash of an existing block to get.").EnableStdin(),
98+
cmds.StringArg("cid", true, false, "The CID of an existing block to get.").EnableStdin(),
9999
},
100100
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
101101
api, err := cmdenv.GetApi(env, req)
@@ -113,32 +113,41 @@ It outputs to stdout, and <key> is a base58 encoded multihash.
113113
}
114114

115115
const (
116-
blockFormatOptionName = "format"
117-
mhtypeOptionName = "mhtype"
118-
mhlenOptionName = "mhlen"
116+
blockFormatOptionName = "format"
117+
blockCidCodecOptionName = "cid-codec"
118+
mhtypeOptionName = "mhtype"
119+
mhlenOptionName = "mhlen"
119120
)
120121

121122
var blockPutCmd = &cmds.Command{
122123
Helptext: cmds.HelpText{
123124
Tagline: "Store input as an IPFS block.",
124125
ShortDescription: `
125126
'ipfs block put' is a plumbing command for storing raw IPFS blocks.
126-
It reads from stdin, and outputs the block's CID to stdout.
127+
It reads data from stdin, and outputs the block's CID to stdout.
127128
128-
Unless specified, this command returns dag-pb CIDv0 CIDs. Setting 'mhtype' to anything
129-
other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1.
129+
Unless cid-codec is specified, this command returns raw (0x55) CIDv1 CIDs.
130+
131+
Passing alternative --cid-codec does not modify imported data, nor run any
132+
validation. It is provided solely for convenience for users who create blocks
133+
in userland.
134+
135+
NOTE:
136+
Do not use --format for any new code. It got superseded by --cid-codec and left
137+
only for backward compatibility when a legacy CIDv0 is required (--format=v0).
130138
`,
131139
},
132140

133141
Arguments: []cmds.Argument{
134142
cmds.FileArg("data", true, true, "The data to be stored as an IPFS block.").EnableStdin(),
135143
},
136144
Options: []cmds.Option{
137-
cmds.StringOption(blockFormatOptionName, "f", "cid format for blocks to be created with."),
138-
cmds.StringOption(mhtypeOptionName, "multihash hash function").WithDefault("sha2-256"),
139-
cmds.IntOption(mhlenOptionName, "multihash hash length").WithDefault(-1),
140-
cmds.BoolOption(pinOptionName, "pin added blocks recursively").WithDefault(false),
145+
cmds.StringOption(blockCidCodecOptionName, "Multicodec to use in returned CID").WithDefault("raw"),
146+
cmds.StringOption(mhtypeOptionName, "Multihash hash function").WithDefault("sha2-256"),
147+
cmds.IntOption(mhlenOptionName, "Multihash hash length").WithDefault(-1),
148+
cmds.BoolOption(pinOptionName, "Pin added blocks recursively").WithDefault(false),
141149
cmdutils.AllowBigBlockOption,
150+
cmds.StringOption(blockFormatOptionName, "f", "Use legacy format for returned CID (DEPRECATED)"),
142151
},
143152
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
144153
api, err := cmdenv.GetApi(env, req)
@@ -157,13 +166,15 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1
157166
return errors.New("missing option \"mhlen\"")
158167
}
159168

160-
format, formatSet := req.Options[blockFormatOptionName].(string)
161-
if !formatSet {
162-
if mhtval != mh.SHA2_256 || (mhlen != -1 && mhlen != 32) {
163-
format = "protobuf"
164-
} else {
165-
format = "v0"
169+
cidCodec, _ := req.Options[blockCidCodecOptionName].(string)
170+
format, _ := req.Options[blockFormatOptionName].(string) // deprecated
171+
172+
// use of legacy 'format' needs to supress 'cid-codec'
173+
if format != "" {
174+
if cidCodec != "" && cidCodec != "raw" {
175+
return fmt.Errorf("unable to use %q (deprecated) and a custom %q at the same time", blockFormatOptionName, blockCidCodecOptionName)
166176
}
177+
cidCodec = "" // makes it no-op
167178
}
168179

169180
pin, _ := req.Options[pinOptionName].(bool)
@@ -177,6 +188,7 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1
177188

178189
p, err := api.Block().Put(req.Context, file,
179190
options.Block.Hash(mhtval, mhlen),
191+
options.Block.CidCodec(cidCodec),
180192
options.Block.Format(format),
181193
options.Block.Pin(pin))
182194
if err != nil {
@@ -219,14 +231,14 @@ type removedBlock struct {
219231

220232
var blockRmCmd = &cmds.Command{
221233
Helptext: cmds.HelpText{
222-
Tagline: "Remove IPFS block(s).",
234+
Tagline: "Remove IPFS block(s) from the local datastore.",
223235
ShortDescription: `
224236
'ipfs block rm' is a plumbing command for removing raw ipfs blocks.
225-
It takes a list of base58 encoded multihashes to remove.
237+
It takes a list of CIDs to remove from the local datastore..
226238
`,
227239
},
228240
Arguments: []cmds.Argument{
229-
cmds.StringArg("hash", true, true, "Bash58 encoded multihash of block(s) to remove."),
241+
cmds.StringArg("cid", true, true, "CIDs of block(s) to remove."),
230242
},
231243
Options: []cmds.Option{
232244
cmds.BoolOption(forceOptionName, "f", "Ignore nonexistent blocks."),

core/commands/cid.go

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ import (
1111
cidutil "github.com/ipfs/go-cidutil"
1212
cmds "github.com/ipfs/go-ipfs-cmds"
1313
verifcid "github.com/ipfs/go-verifcid"
14+
"github.com/ipld/go-ipld-prime/multicodec"
1415
mbase "github.com/multiformats/go-multibase"
16+
mc "github.com/multiformats/go-multicodec"
1517
mhash "github.com/multiformats/go-multihash"
1618
)
1719

@@ -46,7 +48,7 @@ The optional format string is a printf style format string:
4648
` + cidutil.FormatRef,
4749
},
4850
Arguments: []cmds.Argument{
49-
cmds.StringArg("cid", true, true, "Cids to format.").EnableStdin(),
51+
cmds.StringArg("cid", true, true, "CIDs to format.").EnableStdin(),
5052
},
5153
Options: []cmds.Option{
5254
cmds.StringOption(cidFormatOptionName, "Printf style format string.").WithDefault("%s"),
@@ -63,14 +65,14 @@ The optional format string is a printf style format string:
6365
opts := cidFormatOpts{}
6466

6567
if strings.IndexByte(fmtStr, '%') == -1 {
66-
return fmt.Errorf("invalid format string: %s", fmtStr)
68+
return fmt.Errorf("invalid format string: %q", fmtStr)
6769
}
6870
opts.fmtStr = fmtStr
6971

7072
if codecStr != "" {
7173
codec, ok := cid.Codecs[codecStr]
7274
if !ok {
73-
return fmt.Errorf("unknown IPLD codec: %s", codecStr)
75+
return fmt.Errorf("unknown IPLD codec: %q", codecStr)
7476
}
7577
opts.newCodec = codec
7678
} // otherwise, leave it as 0 (not a valid IPLD codec)
@@ -80,13 +82,13 @@ The optional format string is a printf style format string:
8082
// noop
8183
case "0":
8284
if opts.newCodec != 0 && opts.newCodec != cid.DagProtobuf {
83-
return fmt.Errorf("cannot convert to CIDv0 with any codec other than DagPB")
85+
return fmt.Errorf("cannot convert to CIDv0 with any codec other than dag-pb")
8486
}
8587
opts.verConv = toCidV0
8688
case "1":
8789
opts.verConv = toCidV1
8890
default:
89-
return fmt.Errorf("invalid cid version: %s", verStr)
91+
return fmt.Errorf("invalid cid version: %q", verStr)
9092
}
9193

9294
if baseStr != "" {
@@ -123,9 +125,13 @@ type CidFormatRes struct {
123125
var base32Cmd = &cmds.Command{
124126
Helptext: cmds.HelpText{
125127
Tagline: "Convert CIDs to Base32 CID version 1.",
128+
ShortDescription: `
129+
'ipfs cid base32' normalizes passes CIDs to their canonical case-insensitive encoding.
130+
Useful when processing third-party CIDs which could come with arbitrary formats.
131+
`,
126132
},
127133
Arguments: []cmds.Argument{
128-
cmds.StringArg("cid", true, true, "Cids to convert.").EnableStdin(),
134+
cmds.StringArg("cid", true, true, "CIDs to convert.").EnableStdin(),
129135
},
130136
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
131137
opts := cidFormatOpts{
@@ -232,7 +238,7 @@ func emitCids(req *cmds.Request, resp cmds.ResponseEmitter, opts cidFormatOpts)
232238

233239
func toCidV0(c cid.Cid) (cid.Cid, error) {
234240
if c.Type() != cid.DagProtobuf {
235-
return cid.Cid{}, fmt.Errorf("can't convert non-protobuf nodes to cidv0")
241+
return cid.Cid{}, fmt.Errorf("can't convert non-dag-pb nodes to cidv0")
236242
}
237243
return cid.NewCidV0(c.Hash()), nil
238244
}
@@ -254,6 +260,9 @@ const (
254260
var basesCmd = &cmds.Command{
255261
Helptext: cmds.HelpText{
256262
Tagline: "List available multibase encodings.",
263+
ShortDescription: `
264+
'ipfs cid bases' relies on https://github.com/multiformats/go-multibase
265+
`,
257266
},
258267
Options: []cmds.Option{
259268
cmds.BoolOption(prefixOptionName, "also include the single letter prefixes in addition to the code"),
@@ -296,21 +305,45 @@ var basesCmd = &cmds.Command{
296305
}
297306

298307
const (
299-
codecsNumericOptionName = "numeric"
308+
codecsNumericOptionName = "numeric"
309+
codecsSupportedOptionName = "supported"
300310
)
301311

302312
var codecsCmd = &cmds.Command{
303313
Helptext: cmds.HelpText{
304314
Tagline: "List available CID codecs.",
315+
ShortDescription: `
316+
'ipfs cid codecs' relies on https://github.com/multiformats/go-multicodec
317+
`,
305318
},
306319
Options: []cmds.Option{
307-
cmds.BoolOption(codecsNumericOptionName, "also include numeric codes"),
320+
cmds.BoolOption(codecsNumericOptionName, "n", "also include numeric codes"),
321+
cmds.BoolOption(codecsSupportedOptionName, "s", "list only codecs supported by go-ipfs commands"),
308322
},
309323
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {
324+
listSupported, _ := req.Options[codecsSupportedOptionName].(bool)
325+
supportedCodecs := make(map[uint64]struct{})
326+
if listSupported {
327+
for _, code := range multicodec.ListEncoders() {
328+
supportedCodecs[code] = struct{}{}
329+
}
330+
for _, code := range multicodec.ListDecoders() {
331+
supportedCodecs[code] = struct{}{}
332+
}
333+
// add libp2p-key
334+
supportedCodecs[uint64(mc.Libp2pKey)] = struct{}{}
335+
}
336+
310337
var res []CodeAndName
311-
// use CodecToStr as there are multiple names for a given code
312-
for code, name := range cid.CodecToStr {
313-
res = append(res, CodeAndName{int(code), name})
338+
for _, code := range mc.KnownCodes() {
339+
if code.Tag() == "ipld" {
340+
if listSupported {
341+
if _, ok := supportedCodecs[uint64(code)]; !ok {
342+
continue
343+
}
344+
}
345+
res = append(res, CodeAndName{int(code), mc.Code(code).String()})
346+
}
314347
}
315348
return cmds.EmitOnce(resp, res)
316349
},
@@ -334,6 +367,9 @@ var codecsCmd = &cmds.Command{
334367
var hashesCmd = &cmds.Command{
335368
Helptext: cmds.HelpText{
336369
Tagline: "List available multihashes.",
370+
ShortDescription: `
371+
'ipfs cid hashes' relies on https://github.com/multiformats/go-multihash
372+
`,
337373
},
338374
Options: codecsCmd.Options,
339375
Run: func(req *cmds.Request, resp cmds.ResponseEmitter, env cmds.Environment) error {

core/coreapi/block.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc
3131
ctx, span := tracing.Span(ctx, "CoreAPI.BlockAPI", "Put")
3232
defer span.End()
3333

34-
settings, pref, err := caopts.BlockPutOptions(opts...)
34+
settings, err := caopts.BlockPutOptions(opts...)
3535
if err != nil {
3636
return nil, err
3737
}
@@ -41,7 +41,7 @@ func (api *BlockAPI) Put(ctx context.Context, src io.Reader, opts ...caopts.Bloc
4141
return nil, err
4242
}
4343

44-
bcid, err := pref.Sum(data)
44+
bcid, err := settings.CidPrefix.Sum(data)
4545
if err != nil {
4646
return nil, err
4747
}

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ require (
5757
github.com/ipfs/go-unixfs v0.3.1
5858
github.com/ipfs/go-unixfsnode v1.1.3
5959
github.com/ipfs/go-verifcid v0.0.1
60-
github.com/ipfs/interface-go-ipfs-core v0.6.2
60+
github.com/ipfs/interface-go-ipfs-core v0.7.0
6161
github.com/ipfs/tar-utils v0.0.2
6262
github.com/ipld/go-car v0.3.2
6363
github.com/ipld/go-car/v2 v2.1.1
@@ -96,7 +96,7 @@ require (
9696
github.com/multiformats/go-multiaddr v0.5.0
9797
github.com/multiformats/go-multiaddr-dns v0.3.1
9898
github.com/multiformats/go-multibase v0.0.3
99-
github.com/multiformats/go-multicodec v0.4.0
99+
github.com/multiformats/go-multicodec v0.4.1
100100
github.com/multiformats/go-multihash v0.1.0
101101
github.com/opentracing/opentracing-go v1.2.0
102102
github.com/pkg/errors v0.9.1

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -605,8 +605,8 @@ github.com/ipfs/go-unixfsnode v1.1.3/go.mod h1:ZZxUM5wXBC+G0Co9FjrYTOm+UlhZTjxLf
605605
github.com/ipfs/go-verifcid v0.0.1 h1:m2HI7zIuR5TFyQ1b79Da5N9dnnCP1vcu2QqawmWlK2E=
606606
github.com/ipfs/go-verifcid v0.0.1/go.mod h1:5Hrva5KBeIog4A+UpqlaIU+DEstipcJYQQZc0g37pY0=
607607
github.com/ipfs/interface-go-ipfs-core v0.4.0/go.mod h1:UJBcU6iNennuI05amq3FQ7g0JHUkibHFAfhfUIy927o=
608-
github.com/ipfs/interface-go-ipfs-core v0.6.2 h1:nnkq9zhb5O8lPzkZeynEymc83RqkTRqfYH4x5JNUkT4=
609-
github.com/ipfs/interface-go-ipfs-core v0.6.2/go.mod h1:h3NuO3wzv2KuKazt0zDF2/i8AFRqiKHusyh5DUQQdPA=
608+
github.com/ipfs/interface-go-ipfs-core v0.7.0 h1:7tb+2upz8oCcjIyjo1atdMk+P+u7wPmI+GksBlLE8js=
609+
github.com/ipfs/interface-go-ipfs-core v0.7.0/go.mod h1:lF27E/nnSPbylPqKVXGZghal2hzifs3MmjyiEjnc9FY=
610610
github.com/ipfs/tar-utils v0.0.2 h1:UNgHB4x/PPzbMkmJi+7EqC9LNMPDztOVSnx1HAqSNg4=
611611
github.com/ipfs/tar-utils v0.0.2/go.mod h1:4qlnRWgTVljIMhSG2SqRYn66NT+3wrv/kZt9V+eqxDM=
612612
github.com/ipld/go-car v0.3.2 h1:V9wt/80FNfbMRWSD98W5br6fyjUAyVgI2lDOTZX16Lg=
@@ -1188,8 +1188,8 @@ github.com/multiformats/go-multibase v0.0.3/go.mod h1:5+1R4eQrT3PkYZ24C3W2Ue2tPw
11881188
github.com/multiformats/go-multicodec v0.2.0/go.mod h1:/y4YVwkfMyry5kFbMTbLJKErhycTIftytRV+llXdyS4=
11891189
github.com/multiformats/go-multicodec v0.3.0/go.mod h1:qGGaQmioCDh+TeFOnxrbU0DaIPw8yFgAZgFG0V7p1qQ=
11901190
github.com/multiformats/go-multicodec v0.3.1-0.20210902112759-1539a079fd61/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
1191-
github.com/multiformats/go-multicodec v0.4.0 h1:fbqb6ky7erjdD+/zaEBJgZWu1i8D6i/wmPywGK7sdow=
1192-
github.com/multiformats/go-multicodec v0.4.0/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
1191+
github.com/multiformats/go-multicodec v0.4.1 h1:BSJbf+zpghcZMZrwTYBGwy0CPcVZGWiC72Cp8bBd4R4=
1192+
github.com/multiformats/go-multicodec v0.4.1/go.mod h1:1Hj/eHRaVWSXiSNNfcEPcwZleTmdNP81xlxDLnWU9GQ=
11931193
github.com/multiformats/go-multihash v0.0.1/go.mod h1:w/5tugSrLEbWqlcgJabL3oHFKTwfvkofsjW2Qa1ct4U=
11941194
github.com/multiformats/go-multihash v0.0.5/go.mod h1:lt/HCbqlQwlPBz7lv0sQCdtfcMtlJvakRUn/0Ual8po=
11951195
github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew=

0 commit comments

Comments
 (0)