Golang不同包下相同结构体类型不匹配问题求助(Hyperledger Fabric)
Fabric BCCSP跨包类型不兼容问题解决
代码片段
import ( "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric-protos-go/common" "github.com/hyperledger/fabric-protos-go/peer" "github.com/hyperledger/fabric-lib-go/bccsp/sw" mspmgmt "github.com/hyperledger/fabric/msp/mgmt" ) // ...省略其他代码 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) if err != nil { log.Fatalf("Failed to create bccsp: %v", err) } bccsp := mspmgmt.GetIdentityDeserializer(channelId, cryptoProvider) if bccsp == nil { log.Fatalf("could not get msp for channel [%s]", channelId) }
报错信息
./signatureValidator.go:30:54: cannot use cryptoProvider (variable of type "github.com/hyperledger/fabric-lib-go/bccsp".BCCSP) as "github.com/hyperledger/fabric/bccsp".BCCSP value in argument to mspmgmt.GetIdentityDeserializer: "github.com/hyperledger/fabric-lib-go/bccsp".BCCSP does not implement "github.com/hyperledger/fabric/bccsp".BCCSP (wrong type for method Decrypt) have Decrypt("github.com/hyperledger/fabric-lib-go/bccsp".Key, []byte, "github.com/hyperledger/fabric-lib-go/bccsp".DecrypterOpts) ([]byte, error) want Decrypt("github.com/hyperledger/fabric/bccsp".Key, []byte, "github.com/hyperledger/fabric/bccsp".DecrypterOpts) ([]byte, error)
问题原因
github.com/hyperledger/fabric-lib-go/bccsp和github.com/hyperledger/fabric/bccsp是两个独立包,尽管定义了同名的BCCSP接口和相关类型,但Go语言中不同包的类型属于完全独立的类型系统,无法直接互换。而mspmgmt.GetIdentityDeserializer依赖的是fabric核心包内的bccsp.BCCSP接口,因此传入fabric-lib-go的实例会触发类型不兼容错误。
另外,由于依赖github.com/hyperledger/fabric/msp/mgmt,Go模块会自动引入整个fabric核心模块,无法通过移除导入来避免冲突。
解决方法
方法一:直接使用fabric核心包的BCCSP实现
这是最简单的方案,放弃fabric-lib-go的sw实现,改用fabric核心包内的bccsp组件:
import ( "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric-protos-go/common" "github.com/hyperledger/fabric-protos-go/peer" // 替换为fabric核心包的sw实现 "github.com/hyperledger/fabric/bccsp/sw" mspmgmt "github.com/hyperledger/fabric/msp/mgmt" ) // ...省略其他代码 // 创建的cryptoProvider直接符合fabric/bccsp.BCCSP类型要求 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) if err != nil { log.Fatalf("Failed to create bccsp: %v", err) } // 直接传入即可,无需类型转换 bccsp := mspmgmt.GetIdentityDeserializer(channelId, cryptoProvider) if bccsp == nil { log.Fatalf("could not get msp for channel [%s]", channelId) }
方法二:编写适配器转换类型
如果必须使用fabric-lib-go的BCCSP实现,可以通过适配器模式将其转换为fabric核心包的BCCSP接口类型:
首先定义适配器结构体,实现fabric核心包的BCCSP和Key接口:
import ( "fmt" fabbccsp "github.com/hyperledger/fabric/bccsp" libbccsp "github.com/hyperledger/fabric-lib-go/bccsp" ) // LibBCCSPAdapter 适配fabric-lib-go的BCCSP到fabric核心包的BCCSP接口 type LibBCCSPAdapter struct { libBCCSP libbccsp.BCCSP } // KeyGen 实现fabbccsp.BCCSP的KeyGen方法 func (a *LibBCCSPAdapter) KeyGen(opts fabbccsp.KeyGenOpts) (fabbccsp.Key, error) { libOpts, ok := opts.(libbccsp.KeyGenOpts) if !ok { return nil, fmt.Errorf("unsupported key gen opts type") } key, err := a.libBCCSP.KeyGen(libOpts) if err != nil { return nil, err } return &LibKeyAdapter{libKey: key}, nil } // Decrypt 实现fabbccsp.BCCSP的Decrypt方法 func (a *LibBCCSPAdapter) Decrypt(key fabbccsp.Key, ciphertext []byte, opts fabbccsp.DecrypterOpts) ([]byte, error) { libKey, ok := key.(*LibKeyAdapter) if !ok { return nil, fmt.Errorf("unsupported key type") } libOpts, ok := opts.(libbccsp.DecrypterOpts) if !ok { return nil, fmt.Errorf("unsupported decrypt opts type") } return a.libBCCSP.Decrypt(libKey.libKey, ciphertext, libOpts) } // 需实现fabbccsp.BCCSP的所有方法:Encrypt, Sign, Verify, Hash, GetKey, KeyDeriv, KeyImport // 以下为示例,其余方法需按相同逻辑补充 func (a *LibBCCSPAdapter) Encrypt(key fabbccsp.Key, plaintext []byte, opts fabbccsp.EncrypterOpts) ([]byte, error) { libKey, ok := key.(*LibKeyAdapter) if !ok { return nil, fmt.Errorf("unsupported key type") } libOpts, ok := opts.(libbccsp.EncrypterOpts) if !ok { return nil, fmt.Errorf("unsupported encrypt opts type") } return a.libBCCSP.Encrypt(libKey.libKey, plaintext, libOpts) } // LibKeyAdapter 适配fabric-lib-go的Key到fabric核心包的Key接口 type LibKeyAdapter struct { libKey libbccsp.Key } func (k *LibKeyAdapter) Bytes() ([]byte, error) { return k.libKey.Bytes() } func (k *LibKeyAdapter) SKI() []byte { return k.libKey.SKI() } func (k *LibKeyAdapter) Symmetric() bool { return k.libKey.Symmetric() } func (k *LibKeyAdapter) Private() bool { return k.libKey.Private() } func (k *LibKeyAdapter) Public() (fabbccsp.Key, error) { pubKey, err := k.libKey.Public() if err != nil { return nil, err } return &LibKeyAdapter{libKey: pubKey}, nil }
然后在代码中使用适配器:
cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) if err != nil { log.Fatalf("Failed to create bccsp: %v", err) } // 将fabric-lib-go的BCCSP包装为fabric核心包的BCCSP类型 adaptedBCCSP := &LibBCCSPAdapter{libBCCSP: cryptoProvider} bccsp := mspmgmt.GetIdentityDeserializer(channelId, adaptedBCCSP) if bccsp == nil { log.Fatalf("could not get msp for channel [%s]", channelId) }
补充说明
Fabric在版本迭代中,将部分通用组件提取到fabric-lib-go库中,但核心模块(如MSP管理)尚未完全迁移到依赖fabric-lib-go的组件,因此出现了接口重复定义的过渡性问题。优先推荐方法一,避免额外的适配器开发成本;若业务依赖fabric-lib-go的特定功能,再使用方法二。
内容的提问来源于stack exchange,提问作者André Avelar
相关产品推荐
相关产品推荐

