diff --git a/share/shwap/p2p/bitswap/bitswap.go b/share/shwap/p2p/bitswap/bitswap.go index d192cc457c..6ffa2cb8ab 100644 --- a/share/shwap/p2p/bitswap/bitswap.go +++ b/share/shwap/p2p/bitswap/bitswap.go @@ -3,14 +3,14 @@ package bitswap import ( "context" "fmt" + "hash" "sync" "github.com/ipfs/boxo/exchange" blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" logger "github.com/ipfs/go-log/v2" - - "github.com/celestiaorg/rsmt2d" + mh "github.com/multiformats/go-multihash" "github.com/celestiaorg/celestia-node/share" ) @@ -18,22 +18,30 @@ import ( var log = logger.Logger("shwap/bitswap") // TODO: -// * Generalize CIDs handling // * Synchronization for GetContainers // * Test with race and count 100 +// * Hasher test // * Coverage // * godoc // * document steps required to add new id/container type -// ID -// Must avoid duplication of computation and allocation type ID[C any] interface { String() string CID() cid.Cid - BlockFromEDS(*rsmt2d.ExtendedDataSquare) (blocks.Block, error) UnmarshalContainer(*share.Root, []byte) (C, error) } +func RegisterID(mhcode, codec uint64, size int, bldrFn func(cid2 cid.Cid) (blockBuilder, error)) { + mh.Register(mhcode, func() hash.Hash { + return &hasher{IDSize: size} + }) + specRegistry[mhcode] = idSpec{ + size: size, + codec: codec, + builder: bldrFn, + } +} + // GetContainers // Does not guarantee synchronization. Calling this func simultaneously with the same ID may cause // issues. TODO: Describe motivation diff --git a/share/shwap/p2p/bitswap/bitswap_test.go b/share/shwap/p2p/bitswap/bitswap_test.go index cb9b07ec17..631c29d19c 100644 --- a/share/shwap/p2p/bitswap/bitswap_test.go +++ b/share/shwap/p2p/bitswap/bitswap_test.go @@ -58,31 +58,17 @@ func newTestBlockstore(eds *rsmt2d.ExtendedDataSquare) *testBlockstore { } func (b *testBlockstore) Get(_ context.Context, cid cid.Cid) (blocks.Block, error) { - switch cid.Type() { - case sampleCodec: - sid, err := SampleIDFromCID(cid) - if err != nil { - return nil, fmt.Errorf("while converting CID to SampleID: %w", err) - } - - return sid.BlockFromEDS(b.eds) - case rowCodec: - rid, err := RowIDFromCID(cid) - if err != nil { - return nil, fmt.Errorf("while converting CID to RowID: %w", err) - } - - return rid.BlockFromEDS(b.eds) - case rowNamespaceDataCodec: - did, err := RowNamespaceDataIDFromCID(cid) - if err != nil { - return nil, fmt.Errorf("while converting CID to DataID: %w", err) - } - - return did.BlockFromEDS(b.eds) - default: + spec, ok := specRegistry[cid.Prefix().MhType] + if !ok { return nil, fmt.Errorf("unsupported codec") } + + bldr, err := spec.builder(cid) + if err != nil { + return nil, err + } + + return bldr.BlockFromEDS(b.eds) } func (b *testBlockstore) GetSize(ctx context.Context, cid cid.Cid) (int, error) { diff --git a/share/shwap/p2p/bitswap/hasher_test.go b/share/shwap/p2p/bitswap/hasher_test.go index 0ae51a5a39..67a03afb70 100644 --- a/share/shwap/p2p/bitswap/hasher_test.go +++ b/share/shwap/p2p/bitswap/hasher_test.go @@ -1,44 +1 @@ package bitswap - -// func TestHasher(t *testing.T) { -// const size = 8 -// namespace := sharetest.RandV0Namespace() -// square, root := edstest.RandEDSWithNamespace(t, namespace, size*size, size) -// -// data, err := shwap.NamespacedDataFromEDS(square, namespace) -// require.NoError(t, err) -// // TODO(@Wondertan): Reconsider adding RowIdx to RowNamespaceData so that we don't guess it here -// did, err := shwap.NewRowNamespaceDataID(1, 0, namespace, root) -// require.NoError(t, err) -// -// rowData := data[0] -// err = rowData.Validate(root, namespace, int(did.RowIndex)) -// require.NoError(t, err) -// -// blk := RowNamespaceDataBlock{RowNamespaceDataID: did, RowNamespaceData: rowData} -// proto := blk.Proto() -// bin, err := proto.Marshal() -// require.NoError(t, err) -// -// hasher, err := mh.GetHasher(rowNamespaceDataMultihashCode) -// require.NoError(t, err) -// -// _, err = hasher.Write([]byte("hello")) -// assert.Error(t, err) -// -// addRoot(did.Height, root) -// defer deleteRoot(did.Height) -// -// n, err := hasher.Write(bin) -// require.NoError(t, err) -// assert.EqualValues(t, len(bin), n) -// -// digest := hasher.Sum(nil) -// idBin, err := did.MarshalBinary() -// require.NoError(t, err) -// assert.EqualValues(t, idBin, digest) -// -// hasher.Reset() -// digest = hasher.Sum(nil) -// assert.NotEqualValues(t, digest, idBin) -// } diff --git a/share/shwap/p2p/bitswap/cid.go b/share/shwap/p2p/bitswap/id_registry.go similarity index 64% rename from share/shwap/p2p/bitswap/cid.go rename to share/shwap/p2p/bitswap/id_registry.go index 0d2def85cf..6d9ced3c69 100644 --- a/share/shwap/p2p/bitswap/cid.go +++ b/share/shwap/p2p/bitswap/id_registry.go @@ -4,12 +4,25 @@ import ( "encoding" "fmt" + blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" mh "github.com/multiformats/go-multihash" - "github.com/celestiaorg/celestia-node/share/shwap" + "github.com/celestiaorg/rsmt2d" ) +var specRegistry = make(map[uint64]idSpec) + +type idSpec struct { + size int + codec uint64 + builder func(cid.Cid) (blockBuilder, error) +} + +type blockBuilder interface { + BlockFromEDS(*rsmt2d.ExtendedDataSquare) (blocks.Block, error) +} + // DefaultAllowlist keeps default list of multihashes allowed in the network. // TODO(@Wondertan): Make it private and instead provide Blockservice constructor with injected // allowlist @@ -18,12 +31,9 @@ var DefaultAllowlist allowlist type allowlist struct{} func (a allowlist) IsAllowed(code uint64) bool { - // we disable all codes except home-baked - switch code { - case rowMultihashCode, sampleMultihashCode, rowNamespaceDataMultihashCode: - return true - } - return false + // we disable all codes except registered + _, ok := specRegistry[code] + return ok } func extractCID(cid cid.Cid) ([]byte, error) { @@ -51,20 +61,17 @@ func encodeCID(bm encoding.BinaryMarshaler, mhcode, codec uint64) cid.Cid { func validateCID(cid cid.Cid) error { prefix := cid.Prefix() - if !DefaultAllowlist.IsAllowed(prefix.MhType) { + spec, ok := specRegistry[prefix.MhType] + if !ok { return fmt.Errorf("unsupported multihash type %d", prefix.MhType) } - switch prefix.Codec { - default: - return fmt.Errorf("unsupported codec %d", prefix.Codec) - case rowCodec, sampleCodec, rowNamespaceDataCodec: + if prefix.Codec != spec.codec { + return fmt.Errorf("invalid CID codec %d", prefix.Codec) } - switch prefix.MhLength { - default: - return fmt.Errorf("unsupported multihash length %d", prefix.MhLength) - case shwap.RowIDSize, shwap.SampleIDSize, shwap.RowNamespaceDataIDSize: + if prefix.MhLength != spec.size { + return fmt.Errorf("invalid multihash length %d", prefix.MhLength) } return nil diff --git a/share/shwap/p2p/bitswap/row.go b/share/shwap/p2p/bitswap/row.go index 6d4d61649a..508bcaf49d 100644 --- a/share/shwap/p2p/bitswap/row.go +++ b/share/shwap/p2p/bitswap/row.go @@ -2,11 +2,9 @@ package bitswap import ( "fmt" - "hash" blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" - mh "github.com/multiformats/go-multihash" "github.com/celestiaorg/rsmt2d" @@ -24,9 +22,14 @@ const ( ) func init() { - mh.Register(rowMultihashCode, func() hash.Hash { - return &hasher{IDSize: shwap.RowIDSize} - }) + RegisterID( + rowMultihashCode, + rowCodec, + shwap.RowIDSize, + func(cid cid.Cid) (blockBuilder, error) { + return RowIDFromCID(cid) + }, + ) } type RowID shwap.RowID diff --git a/share/shwap/p2p/bitswap/row_namespace_data.go b/share/shwap/p2p/bitswap/row_namespace_data.go index 5f1e1db0a9..f9b366956d 100644 --- a/share/shwap/p2p/bitswap/row_namespace_data.go +++ b/share/shwap/p2p/bitswap/row_namespace_data.go @@ -2,11 +2,9 @@ package bitswap import ( "fmt" - "hash" blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" - mh "github.com/multiformats/go-multihash" "github.com/celestiaorg/rsmt2d" @@ -24,9 +22,14 @@ const ( ) func init() { - mh.Register(rowNamespaceDataMultihashCode, func() hash.Hash { - return &hasher{IDSize: shwap.RowNamespaceDataIDSize} - }) + RegisterID( + rowNamespaceDataMultihashCode, + rowNamespaceDataCodec, + shwap.RowNamespaceDataIDSize, + func(cid cid.Cid) (blockBuilder, error) { + return RowNamespaceDataIDFromCID(cid) + }, + ) } type RowNamespaceDataID shwap.RowNamespaceDataID diff --git a/share/shwap/p2p/bitswap/sample.go b/share/shwap/p2p/bitswap/sample.go index 0d3996d318..91cb287991 100644 --- a/share/shwap/p2p/bitswap/sample.go +++ b/share/shwap/p2p/bitswap/sample.go @@ -2,11 +2,9 @@ package bitswap import ( "fmt" - "hash" blocks "github.com/ipfs/go-block-format" "github.com/ipfs/go-cid" - mh "github.com/multiformats/go-multihash" "github.com/celestiaorg/rsmt2d" @@ -25,9 +23,14 @@ const ( ) func init() { - mh.Register(sampleMultihashCode, func() hash.Hash { - return &hasher{IDSize: shwap.SampleIDSize} - }) + RegisterID( + sampleMultihashCode, + sampleCodec, + shwap.SampleIDSize, + func(cid cid.Cid) (blockBuilder, error) { + return SampleIDFromCID(cid) + }, + ) } type SampleID shwap.SampleID