Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions core/commands/bitswap.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ Print out all blocks currently on the bitswap wantlist for the local peer.`,
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *KeyList) error {
enc, err := cmdenv.GetLowLevelCidEncoder(req)
enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}
Expand Down Expand Up @@ -128,7 +128,7 @@ var bitswapStatCmd = &cmds.Command{
},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, s *bitswap.Stat) error {
enc, err := cmdenv.GetLowLevelCidEncoder(req)
enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}
Expand Down
23 changes: 19 additions & 4 deletions core/commands/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,11 @@ on raw IPFS blocks. It outputs the following to stdout:
return err
}

enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}

p, err := cmdutils.PathOrCidPath(req.Arguments[0])
if err != nil {
return err
Expand All @@ -78,7 +83,7 @@ on raw IPFS blocks. It outputs the following to stdout:
}

return cmds.EmitOnce(res, &BlockStat{
Key: b.Path().RootCid().String(),
Key: enc.Encode(b.Path().RootCid()),
Size: b.Size(),
})
},
Expand Down Expand Up @@ -171,6 +176,11 @@ only for backward compatibility when a legacy CIDv0 is required (--format=v0).
return err
}

enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}

nd, err := cmdenv.GetNode(env)
if err != nil {
return err
Expand Down Expand Up @@ -230,7 +240,7 @@ only for backward compatibility when a legacy CIDv0 is required (--format=v0).
}

err = res.Emit(&BlockStat{
Key: p.Path().RootCid().String(),
Key: enc.Encode(p.Path().RootCid()),
Size: p.Size(),
})
if err != nil {
Expand Down Expand Up @@ -280,6 +290,11 @@ It takes a list of CIDs to remove from the local datastore..
return err
}

enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}

force, _ := req.Options[forceOptionName].(bool)
quiet, _ := req.Options[blockQuietOptionName].(bool)

Expand All @@ -298,7 +313,7 @@ It takes a list of CIDs to remove from the local datastore..
err = api.Block().Rm(req.Context, rp, options.Block.Force(force))
if err != nil {
if err := res.Emit(&removedBlock{
Hash: rp.RootCid().String(),
Hash: enc.Encode(rp.RootCid()),
Error: err.Error(),
}); err != nil {
return err
Expand All @@ -308,7 +323,7 @@ It takes a list of CIDs to remove from the local datastore..

if !quiet {
err := res.Emit(&removedBlock{
Hash: rp.RootCid().String(),
Hash: enc.Encode(rp.RootCid()),
})
if err != nil {
return err
Expand Down
33 changes: 17 additions & 16 deletions core/commands/cmdenv/cidbase.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,20 @@ import (
)

var (
OptionCidBase = cmds.StringOption("cid-base", "Multibase encoding used for version 1 CIDs in output.")
OptionUpgradeCidV0InOutput = cmds.BoolOption("upgrade-cidv0-in-output", "Upgrade version 0 to version 1 CIDs in output.")
OptionCidBase = cmds.StringOption("cid-base", "Multibase encoding for CIDs in output. CIDv0 is automatically converted to CIDv1 when a base other than base58btc is specified.")

// OptionUpgradeCidV0InOutput is deprecated. When --cid-base is set to
// anything other than base58btc, CIDv0 are now automatically upgraded
// to CIDv1. This flag is kept for backward compatibility and will be
// removed in a future release.
OptionUpgradeCidV0InOutput = cmds.BoolOption("upgrade-cidv0-in-output", "[DEPRECATED] Upgrade version 0 to version 1 CIDs in output.")
)

// GetCidEncoder processes the `cid-base` and `output-cidv1` options and
// returns an encoder to use based on those parameters.
// GetCidEncoder processes the --cid-base option and returns an encoder.
// When --cid-base is set to a non-base58btc encoding, CIDv0 values are
// automatically upgraded to CIDv1 because CIDv0 can only be represented
// in base58btc.
func GetCidEncoder(req *cmds.Request) (cidenc.Encoder, error) {
return getCidBase(req, true)
}

// GetLowLevelCidEncoder is like GetCidEncoder but meant to be used by lower
// level commands. It differs from GetCidEncoder in that CIDv0 are not, by
// default, auto-upgraded to CIDv1.
func GetLowLevelCidEncoder(req *cmds.Request) (cidenc.Encoder, error) {
return getCidBase(req, false)
}

func getCidBase(req *cmds.Request, autoUpgrade bool) (cidenc.Encoder, error) {
base, _ := req.Options[OptionCidBase.Name()].(string)
upgrade, upgradeDefined := req.Options[OptionUpgradeCidV0InOutput.Name()].(bool)

Expand All @@ -40,11 +36,16 @@ func getCidBase(req *cmds.Request, autoUpgrade bool) (cidenc.Encoder, error) {
if err != nil {
return e, err
}
if autoUpgrade {
// CIDv0 can only be represented in base58btc. When any other
// base is requested, always upgrade CIDv0 to CIDv1 so the
// output actually uses the requested encoding.
if e.Base.Encoding() != mbase.Base58BTC {
e.Upgrade = true
}
}

// Deprecated: --upgrade-cidv0-in-output still works as an explicit
// override for backward compatibility.
if upgradeDefined {
e.Upgrade = upgrade
}
Expand Down
73 changes: 73 additions & 0 deletions core/commands/cmdenv/cidbase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,82 @@ import (
"testing"

cidenc "github.com/ipfs/go-cidutil/cidenc"
cmds "github.com/ipfs/go-ipfs-cmds"
mbase "github.com/multiformats/go-multibase"
)

func TestGetCidEncoder(t *testing.T) {
makeReq := func(opts map[string]any) *cmds.Request {
if opts == nil {
opts = map[string]any{}
}
return &cmds.Request{Options: opts}
}

t.Run("no options returns default encoder", func(t *testing.T) {
enc, err := GetCidEncoder(makeReq(nil))
if err != nil {
t.Fatal(err)
}
if enc.Upgrade {
t.Error("expected Upgrade=false with no options")
}
})

t.Run("non-base58btc base auto-upgrades CIDv0", func(t *testing.T) {
enc, err := GetCidEncoder(makeReq(map[string]any{
"cid-base": "base32",
}))
if err != nil {
t.Fatal(err)
}
if !enc.Upgrade {
t.Error("expected Upgrade=true for base32")
}
if enc.Base.Encoding() != mbase.Base32 {
t.Errorf("expected base32 encoding, got %v", enc.Base.Encoding())
}
})

t.Run("base58btc does not auto-upgrade", func(t *testing.T) {
enc, err := GetCidEncoder(makeReq(map[string]any{
"cid-base": "base58btc",
}))
if err != nil {
t.Fatal(err)
}
if enc.Upgrade {
t.Error("expected Upgrade=false for base58btc")
}
})

t.Run("deprecated flag still works as override", func(t *testing.T) {
// Explicitly disable upgrade even with non-base58btc base
enc, err := GetCidEncoder(makeReq(map[string]any{
"cid-base": "base32",
"upgrade-cidv0-in-output": false,
}))
if err != nil {
t.Fatal(err)
}
if enc.Upgrade {
t.Error("expected Upgrade=false when explicitly disabled")
}

// Explicitly enable upgrade even with base58btc
enc, err = GetCidEncoder(makeReq(map[string]any{
"cid-base": "base58btc",
"upgrade-cidv0-in-output": true,
}))
if err != nil {
t.Fatal(err)
}
if !enc.Upgrade {
t.Error("expected Upgrade=true when explicitly enabled")
}
})
}

func TestEncoderFromPath(t *testing.T) {
test := func(path string, expected cidenc.Encoder) {
actual, err := CidEncoderFromPath(path)
Expand Down
63 changes: 10 additions & 53 deletions core/commands/dag/dag.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ into an object of the specified format.
Type: OutputObject{},
Encoders: cmds.EncoderMap{
cmds.Text: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, out *OutputObject) error {
enc, err := cmdenv.GetLowLevelCidEncoder(req)
enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}
Expand Down Expand Up @@ -154,7 +154,7 @@ var DagResolveCmd = &cmds.Command{
// Nope, fallback on the default.
fallthrough
default:
enc, err = cmdenv.GetLowLevelCidEncoder(req)
enc, err = cmdenv.GetCidEncoder(req)
if err != nil {
return err
}
Expand Down Expand Up @@ -246,7 +246,7 @@ Specification of CAR formats: https://ipld.io/specs/transport/car/
return fmt.Errorf("unexpected message from DAG import")
}

enc, err := cmdenv.GetLowLevelCidEncoder(req)
enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}
Expand Down Expand Up @@ -294,57 +294,15 @@ CAR file follows the CARv1 format: https://ipld.io/specs/transport/car/carv1/
},
}

// DagStat is a dag stat command response
// DagStat is a dag stat command response. Cid is stored as a
// pre-encoded string (via GetCidEncoder in the Run handler) so that
// --cid-base is respected and no custom MarshalJSON is needed.
type DagStat struct {
Cid cid.Cid
Cid string `json:"Cid"`
Size uint64 `json:",omitempty"`
NumBlocks int64 `json:",omitempty"`
}

func (s *DagStat) String() string {
return fmt.Sprintf("%s %d %d", s.Cid.String()[:20], s.Size, s.NumBlocks)
}

func (s *DagStat) MarshalJSON() ([]byte, error) {
type Alias DagStat
/*
We can't rely on cid.Cid.MarshalJSON since it uses the {"/": "..."}
format. To make the output consistent and follow the Kubo API patterns
we use the Cid.String method
*/
return json.Marshal(struct {
Cid string `json:"Cid"`
*Alias
}{
Cid: s.Cid.String(),
Alias: (*Alias)(s),
})
}

func (s *DagStat) UnmarshalJSON(data []byte) error {
/*
We can't rely on cid.Cid.UnmarshalJSON since it uses the {"/": "..."}
format. To make the output consistent and follow the Kubo API patterns
we use the Cid.Parse method
*/
type Alias DagStat
aux := struct {
Cid string `json:"Cid"`
*Alias
}{
Alias: (*Alias)(s),
}
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
Cid, err := cid.Parse(aux.Cid)
if err != nil {
return err
}
s.Cid = Cid
return nil
}

type DagStatSummary struct {
redundantSize uint64 `json:"-"`
UniqueBlocks int `json:",omitempty"`
Expand Down Expand Up @@ -406,15 +364,15 @@ Note: This command skips duplicate blocks in reporting both size and the number
fmt.Fprintln(w)
csvWriter := csv.NewWriter(w)
csvWriter.Comma = '\t'
cidSpacing := len(event.DagStatsArray[0].Cid.String())
cidSpacing := len(event.DagStatsArray[0].Cid)
header := []string{fmt.Sprintf("%-*s", cidSpacing, "CID"), fmt.Sprintf("%-15s", "Blocks"), "Size"}
if err := csvWriter.Write(header); err != nil {
return err
}
for _, dagStat := range event.DagStatsArray {
numBlocksStr := fmt.Sprint(dagStat.NumBlocks)
err := csvWriter.Write([]string{
dagStat.Cid.String(),
dagStat.Cid,
fmt.Sprintf("%-15s", numBlocksStr),
fmt.Sprint(dagStat.Size),
})
Expand All @@ -434,7 +392,6 @@ Note: This command skips duplicate blocks in reporting both size and the number
}),
cmds.JSON: cmds.MakeTypedEncoder(func(req *cmds.Request, w io.Writer, event *DagStatSummary) error {
return json.NewEncoder(w).Encode(event)
},
),
}),
},
}
8 changes: 7 additions & 1 deletion core/commands/dag/stat.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ func dagStat(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment)
if err != nil {
return err
}

enc, err := cmdenv.GetCidEncoder(req)
if err != nil {
return err
}

nodeGetter := mdag.NewSession(req.Context, api.Dag())

cidSet := cid.NewSet()
Expand All @@ -50,7 +56,7 @@ func dagStat(req *cmds.Request, res cmds.ResponseEmitter, env cmds.Environment)
if err != nil {
return err
}
dagstats := &DagStat{Cid: rp.RootCid()}
dagstats := &DagStat{Cid: enc.Encode(rp.RootCid())}
dagStatSummary.appendStats(dagstats)
err = traverse.Traverse(obj, traverse.Options{
DAG: nodeGetter,
Expand Down
Loading
Loading