Skip to content

Commit 04e7e95

Browse files
schomatislidel
andauthored
feat(cmds): extend block size check for dag|block put (#8751)
* feat(cmds): extend block size check for dag|block put * feat(cmds): block size check for dag import * style: dag-pb → UnixFS, 1MB → 1MiB Co-authored-by: Marcin Rataj <lidel@lidel.org>
1 parent 0487f03 commit 04e7e95

File tree

11 files changed

+120
-39
lines changed

11 files changed

+120
-39
lines changed

core/commands/block.go

+6
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010

1111
util "github.com/ipfs/go-ipfs/blocks/blockstoreutil"
1212
cmdenv "github.com/ipfs/go-ipfs/core/commands/cmdenv"
13+
"github.com/ipfs/go-ipfs/core/commands/cmdutils"
1314

1415
cmds "github.com/ipfs/go-ipfs-cmds"
1516
options "github.com/ipfs/interface-go-ipfs-core/options"
@@ -138,6 +139,7 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1
138139
cmds.StringOption(mhtypeOptionName, "multihash hash function").WithDefault("sha2-256"),
139140
cmds.IntOption(mhlenOptionName, "multihash hash length").WithDefault(-1),
140141
cmds.BoolOption(pinOptionName, "pin added blocks recursively").WithDefault(false),
142+
cmdutils.AllowBigBlockOption,
141143
},
142144
Run: func(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) error {
143145
api, err := cmdenv.GetApi(env, req)
@@ -182,6 +184,10 @@ other than 'sha2-256' or format to anything other than 'v0' will result in CIDv1
182184
return err
183185
}
184186

187+
if err := cmdutils.CheckBlockSize(req, uint64(p.Size())); err != nil {
188+
return err
189+
}
190+
185191
err = res.Emit(&BlockStat{
186192
Key: p.Path().Cid().String(),
187193
Size: p.Size(),

core/commands/cmdutils/utils.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package cmdutils
2+
3+
import (
4+
"fmt"
5+
6+
cmds "github.com/ipfs/go-ipfs-cmds"
7+
8+
"github.com/ipfs/go-cid"
9+
coreiface "github.com/ipfs/interface-go-ipfs-core"
10+
)
11+
12+
const (
13+
AllowBigBlockOptionName = "allow-big-block"
14+
SoftBlockLimit = 1024 * 1024 // https://github.com/ipfs/go-ipfs/issues/7421#issuecomment-910833499
15+
)
16+
17+
var AllowBigBlockOption cmds.Option
18+
19+
func init() {
20+
AllowBigBlockOption = cmds.BoolOption(AllowBigBlockOptionName, "Disable block size check and allow creation of blocks bigger than 1MiB. WARNING: such blocks won't be transferable over the standard bitswap.").WithDefault(false)
21+
}
22+
23+
func CheckCIDSize(req *cmds.Request, c cid.Cid, dagAPI coreiface.APIDagService) error {
24+
n, err := dagAPI.Get(req.Context, c)
25+
if err != nil {
26+
return fmt.Errorf("CheckCIDSize: getting dag: %w", err)
27+
}
28+
29+
nodeSize, err := n.Size()
30+
if err != nil {
31+
return fmt.Errorf("CheckCIDSize: getting node size: %w", err)
32+
}
33+
34+
return CheckBlockSize(req, nodeSize)
35+
}
36+
37+
func CheckBlockSize(req *cmds.Request, size uint64) error {
38+
allowAnyBlockSize, _ := req.Options[AllowBigBlockOptionName].(bool)
39+
if allowAnyBlockSize {
40+
return nil
41+
}
42+
43+
// We do not allow producing blocks bigger than 1 MiB to avoid errors
44+
// when transmitting them over BitSwap. The 1 MiB constant is an
45+
// unenforced and undeclared rule of thumb hard-coded here.
46+
if size > SoftBlockLimit {
47+
return fmt.Errorf("produced block is over 1MiB: big blocks can't be exchanged with other peers. consider using UnixFS for automatic chunking of bigger files, or pass --allow-big-block to override")
48+
}
49+
return nil
50+
51+
}

core/commands/dag/dag.go

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"io"
66

77
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
8+
"github.com/ipfs/go-ipfs/core/commands/cmdutils"
89

910
cid "github.com/ipfs/go-cid"
1011
cidenc "github.com/ipfs/go-cidutil/cidenc"
@@ -88,6 +89,7 @@ into an object of the specified format.
8889
cmds.StringOption("input-codec", "Codec that the input object is encoded in").WithDefault("dag-json"),
8990
cmds.BoolOption("pin", "Pin this object when adding."),
9091
cmds.StringOption("hash", "Hash function to use").WithDefault("sha2-256"),
92+
cmdutils.AllowBigBlockOption,
9193
},
9294
Run: dagPut,
9395
Type: OutputObject{},
@@ -205,6 +207,7 @@ Maximum supported CAR version: 1
205207
cmds.BoolOption(pinRootsOptionName, "Pin optional roots listed in the .car headers after importing.").WithDefault(true),
206208
cmds.BoolOption(silentOptionName, "No output."),
207209
cmds.BoolOption(statsOptionName, "Output stats."),
210+
cmdutils.AllowBigBlockOption,
208211
},
209212
Type: CarImportOutput{},
210213
Run: dagImport,

core/commands/dag/import.go

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
cid "github.com/ipfs/go-cid"
99
files "github.com/ipfs/go-ipfs-files"
1010
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
11+
"github.com/ipfs/go-ipfs/core/commands/cmdutils"
1112
ipld "github.com/ipfs/go-ipld-format"
1213
iface "github.com/ipfs/interface-go-ipfs-core"
1314
"github.com/ipfs/interface-go-ipfs-core/options"
@@ -180,6 +181,9 @@ func importWorker(req *cmds.Request, re cmds.ResponseEmitter, api iface.CoreAPI,
180181
} else if block == nil {
181182
break
182183
}
184+
if err := cmdutils.CheckBlockSize(req, uint64(len(block.RawData()))); err != nil {
185+
return err
186+
}
183187

184188
// the double-decode is suboptimal, but we need it for batching
185189
nd, err := ipld.Decode(block)

core/commands/dag/put.go

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
blocks "github.com/ipfs/go-block-format"
88
"github.com/ipfs/go-cid"
99
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
10+
"github.com/ipfs/go-ipfs/core/commands/cmdutils"
1011
ipldlegacy "github.com/ipfs/go-ipld-legacy"
1112
"github.com/ipld/go-ipld-prime/multicodec"
1213
basicnode "github.com/ipld/go-ipld-prime/node/basic"
@@ -102,6 +103,10 @@ func dagPut(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment) e
102103
Node: n,
103104
}
104105

106+
if err := cmdutils.CheckBlockSize(req, uint64(bd.Len())); err != nil {
107+
return err
108+
}
109+
105110
if err := b.Add(req.Context, &ln); err != nil {
106111
return err
107112
}

core/commands/get.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ func getCompressOptions(req *cmds.Request) (int, error) {
257257
return cmplvl, nil
258258
}
259259

260-
// DefaultBufSize is the buffer size for gets. for now, 1MB, which is ~4 blocks.
260+
// DefaultBufSize is the buffer size for gets. for now, 1MiB, which is ~4 blocks.
261261
// TODO: does this need to be configurable?
262262
var DefaultBufSize = 1048576
263263

core/commands/object/patch.go

+7-36
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,14 @@ import (
44
"fmt"
55
"io"
66

7-
"github.com/ipfs/go-cid"
87
cmds "github.com/ipfs/go-ipfs-cmds"
98
"github.com/ipfs/go-ipfs/core/commands/cmdenv"
10-
coreiface "github.com/ipfs/interface-go-ipfs-core"
9+
"github.com/ipfs/go-ipfs/core/commands/cmdutils"
1110

1211
"github.com/ipfs/interface-go-ipfs-core/options"
1312
"github.com/ipfs/interface-go-ipfs-core/path"
1413
)
1514

16-
const (
17-
softBlockLimit = 1024 * 1024 // https://github.com/ipfs/go-ipfs/issues/7421#issuecomment-910833499
18-
allowBigBlock = "allow-big-block"
19-
)
20-
2115
var ObjectPatchCmd = &cmds.Command{
2216
Helptext: cmds.HelpText{
2317
Tagline: "Deprecated way to create a new merkledag object based on an existing one. Use MFS with 'files cp|rm' instead.",
@@ -49,7 +43,7 @@ For modern use cases, use MFS with 'files' commands: 'ipfs files --help'.
4943
"set-data": patchSetDataCmd,
5044
},
5145
Options: []cmds.Option{
52-
cmds.BoolOption(allowBigBlock, "Disable block size check and allow creation of blocks bigger than 1MB. WARNING: such blocks won't be transferable over the standard bitswap.").WithDefault(false),
46+
cmdutils.AllowBigBlockOption,
5347
},
5448
}
5549

@@ -64,7 +58,7 @@ Example:
6458
$ echo "hello" | ipfs object patch $HASH append-data
6559
6660
NOTE: This does not append data to a file - it modifies the actual raw
67-
data within a dag-pb object. Blocks have a max size of 1MB and objects larger than
61+
data within a dag-pb object. Blocks have a max size of 1MiB and objects larger than
6862
the limit will not be respected by the network.
6963
7064
DEPRECATED and provided for legacy reasons. Use 'ipfs add' or 'ipfs files' instead.
@@ -92,7 +86,7 @@ DEPRECATED and provided for legacy reasons. Use 'ipfs add' or 'ipfs files' inste
9286
return err
9387
}
9488

95-
if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil {
89+
if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil {
9690
return err
9791
}
9892

@@ -142,7 +136,7 @@ DEPRECATED and provided for legacy reasons. Use 'files cp' and 'dag put' instead
142136
return err
143137
}
144138

145-
if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil {
139+
if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil {
146140
return err
147141
}
148142

@@ -184,7 +178,7 @@ DEPRECATED and provided for legacy reasons. Use 'files rm' instead.
184178
return err
185179
}
186180

187-
if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil {
181+
if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil {
188182
return err
189183
}
190184

@@ -254,7 +248,7 @@ Use MFS and 'files' commands instead:
254248
return err
255249
}
256250

257-
if err := checkBlockSize(req, p.Cid(), api.Dag()); err != nil {
251+
if err := cmdutils.CheckCIDSize(req, p.Cid(), api.Dag()); err != nil {
258252
return err
259253
}
260254

@@ -268,26 +262,3 @@ Use MFS and 'files' commands instead:
268262
}),
269263
},
270264
}
271-
272-
func checkBlockSize(req *cmds.Request, c cid.Cid, dagAPI coreiface.APIDagService) error {
273-
allowAnyBlockSize, _ := req.Options[allowBigBlock].(bool)
274-
if allowAnyBlockSize {
275-
return nil
276-
}
277-
278-
// We do not allow producing blocks bigger than 1 MiB to avoid errors
279-
// when transmitting them over BitSwap. The 1 MiB constant is an
280-
// unenforced and undeclared rule of thumb hard-coded here.
281-
modifiedNode, err := dagAPI.Get(req.Context, c)
282-
if err != nil {
283-
return err
284-
}
285-
modifiedNodeSize, err := modifiedNode.Size()
286-
if err != nil {
287-
return err
288-
}
289-
if modifiedNodeSize > softBlockLimit {
290-
return fmt.Errorf("produced block is over 1MB, object API is deprecated and does not support HAMT-sharding: to create big directories, please use the files API (MFS)")
291-
}
292-
return nil
293-
}

test/sharness/t0050-block.sh

+14
Original file line numberDiff line numberDiff line change
@@ -248,4 +248,18 @@ test_expect_success "put with sha3 and cidv0 fails" '
248248
echo "foooo" | test_must_fail ipfs block put --mhtype=sha3 --mhlen=20 --format=v0
249249
'
250250

251+
test_expect_success "'ipfs block put' check block size" '
252+
dd if=/dev/zero bs=2MB count=1 > 2-MB-file &&
253+
test_expect_code 1 ipfs block put 2-MB-file >block_put_out 2>&1
254+
'
255+
256+
test_expect_success "ipfs block put output has the correct error" '
257+
grep "produced block is over 1MiB" block_put_out
258+
'
259+
260+
test_expect_success "ipfs block put --allow-big-block=true works" '
261+
test_expect_code 0 ipfs block put 2-MB-file --allow-big-block=true &&
262+
rm 2-MB-file
263+
'
264+
251265
test_done

test/sharness/t0051-object.sh

+2-2
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,12 @@ test_object_cmd() {
229229
do
230230
DIR=$(ipfs object patch "$DIR" add-link "$DIR.jpg" "$DIR")
231231
done
232-
# Fail when new block goes over the BS limit of 1MB, but allow manual override
232+
# Fail when new block goes over the BS limit of 1MiB, but allow manual override
233233
test_expect_code 1 ipfs object patch "$DIR" add-link "$DIR.jpg" "$DIR" >patch_out 2>&1
234234
'
235235

236236
test_expect_success "ipfs object patch add-link output has the correct error" '
237-
grep "produced block is over 1MB, object API is deprecated and does not support HAMT-sharding: to create big directories, please use the files API (MFS)" patch_out
237+
grep "produced block is over 1MiB" patch_out
238238
'
239239

240240
test_expect_success "ipfs object patch --allow-big-block=true add-link works" '

test/sharness/t0053-dag.sh

+14
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,20 @@ test_dag_cmd() {
4444
test $EXPHASH = $IPLDHASH
4545
'
4646

47+
test_expect_success "'ipfs dag put' check block size" '
48+
dd if=/dev/zero bs=2MB count=1 > 2-MB-file &&
49+
test_expect_code 1 ipfs dag put --input-codec=raw --store-codec=raw 2-MB-file >dag_put_out 2>&1
50+
'
51+
52+
test_expect_success "ipfs dag put output has the correct error" '
53+
grep "produced block is over 1MiB" dag_put_out
54+
'
55+
56+
test_expect_success "ipfs dag put --allow-big-block=true works" '
57+
test_expect_code 0 ipfs dag put --input-codec=raw --store-codec=raw 2-MB-file --allow-big-block=true &&
58+
rm 2-MB-file
59+
'
60+
4761
test_expect_success "can add an ipld object using dag-json to dag-json" '
4862
IPLDHASH=$(cat ipld_object | ipfs dag put --input-codec dag-json --store-codec dag-json)
4963
'

test/sharness/t0054-dag-car-import-export.sh

+13
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,17 @@ test_expect_success "naked root import expected output" '
233233
test_cmp_sorted naked_root_import_json_expected naked_root_import_json_actual
234234
'
235235

236+
test_expect_success "'ipfs dag import' check block size" '
237+
BIG_CID=$(dd if=/dev/zero bs=2MB count=1 | ipfs dag put --input-codec=raw --store-codec=raw --allow-big-block) &&
238+
ipfs dag export $BIG_CID > 2-MB-block.car &&
239+
test_expect_code 1 ipfs dag import 2-MB-block.car >dag_import_out 2>&1
240+
'
241+
test_expect_success "ipfs dag import output has the correct error" '
242+
grep "block is over 1MiB" dag_import_out
243+
'
244+
245+
test_expect_success "ipfs dag import --allow-big-block works" '
246+
test_expect_code 0 ipfs dag import --allow-big-block 2-MB-block.car
247+
'
248+
236249
test_done

0 commit comments

Comments
 (0)